Browse Source

First release M2Mqtt 3.6.0.0 on Paho

Paolo Patierno 9 years ago
parent
commit
201ff8c9ce
50 changed files with 7286 additions and 0 deletions
  1. 103 0
      M2Mqtt/Exceptions/MqttClientException.cs
  2. 42 0
      M2Mqtt/Exceptions/MqttCommunicationException.cs
  3. 31 0
      M2Mqtt/Exceptions/MqttConnectionException.cs
  4. 27 0
      M2Mqtt/Exceptions/MqttTimeoutException.cs
  5. 56 0
      M2Mqtt/IMqttNetworkChannel.cs
  6. 87 0
      M2Mqtt/M2Mqtt.csproj
  7. 73 0
      M2Mqtt/M2MqttMono.csproj
  8. 108 0
      M2Mqtt/M2MqttNetCf35.csproj
  9. 89 0
      M2Mqtt/M2MqttNetCf39.csproj
  10. 89 0
      M2Mqtt/M2MqttWinRT.csproj
  11. 241 0
      M2Mqtt/Messages/MqttMsgBase.cs
  12. 147 0
      M2Mqtt/Messages/MqttMsgConnack.cs
  13. 525 0
      M2Mqtt/Messages/MqttMsgConnect.cs
  14. 44 0
      M2Mqtt/Messages/MqttMsgConnectEventArgs.cs
  15. 139 0
      M2Mqtt/Messages/MqttMsgContext.cs
  16. 74 0
      M2Mqtt/Messages/MqttMsgDisconnect.cs
  17. 74 0
      M2Mqtt/Messages/MqttMsgPingReq.cs
  18. 75 0
      M2Mqtt/Messages/MqttMsgPingResp.cs
  19. 129 0
      M2Mqtt/Messages/MqttMsgPuback.cs
  20. 128 0
      M2Mqtt/Messages/MqttMsgPubcomp.cs
  21. 280 0
      M2Mqtt/Messages/MqttMsgPublish.cs
  22. 111 0
      M2Mqtt/Messages/MqttMsgPublishEventArgs.cs
  23. 55 0
      M2Mqtt/Messages/MqttMsgPublishedEventArgs.cs
  24. 128 0
      M2Mqtt/Messages/MqttMsgPubrec.cs
  25. 138 0
      M2Mqtt/Messages/MqttMsgPubrel.cs
  26. 163 0
      M2Mqtt/Messages/MqttMsgSuback.cs
  27. 265 0
      M2Mqtt/Messages/MqttMsgSubscribe.cs
  28. 81 0
      M2Mqtt/Messages/MqttMsgSubscribeEventArgs.cs
  29. 68 0
      M2Mqtt/Messages/MqttMsgSubscribedEventArgs.cs
  30. 132 0
      M2Mqtt/Messages/MqttMsgUnsuback.cs
  31. 232 0
      M2Mqtt/Messages/MqttMsgUnsubscribe.cs
  32. 68 0
      M2Mqtt/Messages/MqttMsgUnsubscribeEventArgs.cs
  33. 55 0
      M2Mqtt/Messages/MqttMsgUnsubscribedEventArgs.cs
  34. 2140 0
      M2Mqtt/MqttClient.cs
  35. 96 0
      M2Mqtt/MqttSettings.cs
  36. 36 0
      M2Mqtt/Net/Fx.cs
  37. 320 0
      M2Mqtt/Net/MqttNetworkChannel.cs
  38. 44 0
      M2Mqtt/Properties/AssemblyInfo.cs
  39. 50 0
      M2Mqtt/Utility/QueueExtension.cs
  40. 85 0
      M2Mqtt/Utility/Trace.cs
  41. 36 0
      M2Mqtt/WinRT/Fx.cs
  42. 106 0
      M2Mqtt/WinRT/MqttNetworkChannel.cs
  43. 27 0
      M2Mqtt/WinRT/Queue.cs
  44. 77 0
      M2Mqtt/uM2MqttNetMf42.csproj
  45. 77 0
      M2Mqtt/uM2MqttNetMf43.csproj
  46. 20 0
      M2MqttMono.sln
  47. 20 0
      M2MqttVS2008.sln
  48. 29 0
      M2MqttVS2010.sln
  49. 38 0
      M2MqttVS2012.sln
  50. 28 0
      M2MqttVS2013.sln

+ 103 - 0
M2Mqtt/Exceptions/MqttClientException.cs

@@ -0,0 +1,103 @@
+/*
+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 topic length error
+        /// </summary>
+        WillTopicWrong = 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
+    }
+}

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

+ 56 - 0
M2Mqtt/IMqttNetworkChannel.cs

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

+ 87 - 0
M2Mqtt/M2Mqtt.csproj

@@ -0,0 +1,87 @@
+<?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</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;SSL</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="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="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="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.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>

+ 73 - 0
M2Mqtt/M2MqttMono.csproj

@@ -0,0 +1,73 @@
+<?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</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\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\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="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\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.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="Properties\AssemblyInfo.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+	<Compile Include="Utility\Trace.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>

+ 108 - 0
M2Mqtt/M2MqttNetCf35.csproj

@@ -0,0 +1,108 @@
+<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</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\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\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="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="MqttSettings.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="Utility\Trace.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>

+ 89 - 0
M2Mqtt/M2MqttNetCf39.csproj

@@ -0,0 +1,89 @@
+<?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</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\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\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="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="MqttSettings.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="Utility\Trace.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>

+ 89 - 0
M2Mqtt/M2MqttWinRT.csproj

@@ -0,0 +1,89 @@
+<?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</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\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\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="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="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="WinRT\Fx.cs" />
+    <Compile Include="WinRT\MqttNetworkChannel.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>

+ 241 - 0
M2Mqtt/Messages/MqttMsgBase.cs

@@ -0,0 +1,241 @@
+/*
+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 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;
+
+        // 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;
+
+        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; }
+        }
+
+        #endregion
+
+        // message type
+        protected byte type;
+        // duplicate delivery
+        protected bool dupFlag;
+        // quality of service level
+        protected byte qosLevel;
+        // retain flag
+        protected bool retain;
+
+        /// <summary>
+        /// Returns message bytes rapresentation
+        /// </summary>
+        /// <returns>Bytes rapresentation</returns>
+        public abstract byte[] GetBytes();
+        
+        /// <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
+    }
+}

+ 147 - 0
M2Mqtt/Messages/MqttMsgConnack.cs

@@ -0,0 +1,147 @@
+/*
+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.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;
+        private const byte CONN_RETURN_CODE_BYTE_OFFSET = 1;
+        private const byte CONN_RETURN_CODE_BYTE_SIZE = 1;
+
+        #endregion
+
+        #region Properties...
+
+        /// <summary>
+        /// Return Code
+        /// </summary>
+        public byte ReturnCode
+        {
+            get { return this.returnCode; }
+            set { this.returnCode = value; }
+        }
+
+        #endregion
+
+        // 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="channel">Channel connected to the broker</param>
+        /// <returns>CONNACK message instance</returns>
+        public static MqttMsgConnack Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            MqttMsgConnack msg = new MqttMsgConnack();
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+            // ...and set return code from broker
+            msg.returnCode = buffer[CONN_RETURN_CODE_BYTE_OFFSET];
+
+            return msg;
+        }
+
+        public override byte[] GetBytes()
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // 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
+            buffer[index] = (byte)(MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET);
+            index++;
+
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // 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
+        }
+    }
+}

+ 525 - 0
M2Mqtt/Messages/MqttMsgConnect.cs

@@ -0,0 +1,525 @@
+/*
+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 = "MQIsdp";
+
+        // max length for client id
+        internal const int CLIENT_ID_MAX_LENGTH = 23;
+
+        // variable header fields
+        internal const byte PROTOCOL_NAME_LEN_SIZE = 2;
+        internal const byte PROTOCOL_NAME_SIZE = 6;
+        internal const byte PROTOCOL_VERSION_NUMBER_SIZE = 1;
+        internal const byte CONNECT_FLAGS_SIZE = 1;
+        internal const byte KEEP_ALIVE_TIME_SIZE = 2;
+
+        internal const byte PROTOCOL_VERSION = 0x03;
+        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;
+
+        #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;
+
+            this.protocolName = PROTOCOL_NAME;
+            this.protocolVersion = PROTOCOL_VERSION;
+        }
+
+        /// <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)
+        {
+        }
+
+        /// <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>
+        public MqttMsgConnect(string clientId, 
+            string username, 
+            string password,
+            bool willRetain,
+            byte willQosLevel,
+            bool willFlag,
+            string willTopic,
+            string willMessage,
+            bool cleanSession,
+            ushort keepAlivePeriod
+            )
+        {
+            this.type = MQTT_MSG_CONNECT_TYPE;
+
+            this.protocolName = PROTOCOL_NAME;
+            this.protocolVersion = PROTOCOL_VERSION;
+
+            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;
+        }
+
+        /// <summary>
+        /// Parse bytes for a CONNECT message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>CONNECT message instance</returns>
+        public static MqttMsgConnect Parse(byte fixedHeaderFirstByte, 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));
+
+            // protocol version
+            msg.protocolVersion = buffer[index];
+            index += PROTOCOL_VERSION_NUMBER_SIZE;
+
+            // connect flags
+            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
+            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));
+
+            // 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()
+        {
+            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.willTopic != null) ? Encoding.UTF8.GetBytes(this.willTopic) : null;
+            byte[] willMessageUtf8 = (this.willMessage != null) ? Encoding.UTF8.GetBytes(this.willMessage) : null;
+            byte[] usernameUtf8 = (this.username != null) ? Encoding.UTF8.GetBytes(this.username) : null;
+            byte[] passwordUtf8 = (this.password != null) ? Encoding.UTF8.GetBytes(this.password) : null;
+
+            // will flag set but will topic wrong
+            if (this.willFlag && (willTopicUtf8.Length == 0))
+                throw new MqttClientException(MqttClientErrorCode.WillTopicWrong);
+            if (this.keepAlivePeriod > MAX_KEEP_ALIVE)
+                throw new MqttClientException(MqttClientErrorCode.KeepAliveWrong);
+
+            // protocol name field size
+            varHeaderSize += (PROTOCOL_NAME_LEN_SIZE + PROTOCOL_NAME_SIZE);
+            // protocol version number field size
+            varHeaderSize += PROTOCOL_VERSION_NUMBER_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);
+
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // protocol name
+            buffer[index++] = 0; // MSB protocol name size
+            buffer[index++] = PROTOCOL_NAME_SIZE; // LSB protocol name size
+            buffer[index++] = (byte)'M';
+            buffer[index++] = (byte)'Q';
+            buffer[index++] = (byte)'I';
+            buffer[index++] = (byte)'s';
+            buffer[index++] = (byte)'d';
+            buffer[index++] = (byte)'p';
+
+            // protocol version
+            buffer[index++] = PROTOCOL_VERSION;
+
+            // connect flags
+            byte connectFlags = 0x00;
+            connectFlags |= (this.username != null) ? (byte)(1 << USERNAME_FLAG_OFFSET) : (byte)0x00;
+            connectFlags |= (this.password != null) ? (byte)(1 << PASSWORD_FLAG_OFFSET) : (byte)0x00;
+            connectFlags |= (this.willRetain) ? (byte)(1 << WILL_RETAIN_FLAG_OFFSET) : (byte)0x00;
+            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 && (this.willTopic != 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 && (this.willMessage != 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 (this.username != 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 (this.password != 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;
+        }
+    }
+} 

+ 139 - 0
M2Mqtt/Messages/MqttMsgContext.cs

@@ -0,0 +1,139 @@
+/*
+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>
+    /// 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,
+
+        /// <summary>
+        /// (QOS = 1), SUBSCRIBE sent, wait for SUBACK
+        /// </summary>
+        WaitForSuback,
+
+        /// <summary>
+        /// (QOS = 1), UNSUBSCRIBE sent, wait for UNSUBACK
+        /// </summary>
+        WaitForUnsuback
+    }
+}

+ 74 - 0
M2Mqtt/Messages/MqttMsgDisconnect.cs

@@ -0,0 +1,74 @@
+/*
+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.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="channel">Channel connected to the broker</param>
+        /// <returns>DISCONNECT message instance</returns>
+        public static MqttMsgDisconnect Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            MqttMsgDisconnect msg = new MqttMsgDisconnect();
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            // NOTE : remainingLength must be 0
+
+            return msg;
+        }
+
+        public override byte[] GetBytes()
+        {
+            byte[] buffer = new byte[2];
+            int index = 0;
+
+            // first fixed header byte
+            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
+        }
+    }
+}

+ 74 - 0
M2Mqtt/Messages/MqttMsgPingReq.cs

@@ -0,0 +1,74 @@
+/*
+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.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[] buffer = new byte[2];
+            int index = 0;
+
+            // first fixed header byte
+            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="channel">Channel connected to the broker</param>
+        /// <returns>PINGREQ message instance</returns>
+        public static MqttMsgPingReq Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            MqttMsgPingReq msg = new MqttMsgPingReq();
+
+            // 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
+        }
+    }
+}

+ 75 - 0
M2Mqtt/Messages/MqttMsgPingResp.cs

@@ -0,0 +1,75 @@
+/*
+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.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="channel">Channel connected to the broker</param>
+        /// <returns>PINGRESP message instance</returns>
+        public static MqttMsgPingResp Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            MqttMsgPingResp msg = new MqttMsgPingResp();
+
+            // 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[] buffer = new byte[2];
+            int index = 0;
+
+            // first fixed header byte
+            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
+        }
+    }
+}

+ 129 - 0
M2Mqtt/Messages/MqttMsgPuback.cs

@@ -0,0 +1,129 @@
+/*
+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.Messages
+{
+    /// <summary>
+    /// Class for PUBACK message from broker to client
+    /// </summary>
+    public class MqttMsgPuback : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier for the publish message
+        /// that is acknowledged
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        private ushort messageId;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPuback()
+        {
+            this.type = MQTT_MSG_PUBACK_TYPE;
+        }
+
+        public override byte[] GetBytes()
+        {
+            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
+            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="channel">Channel connected to the broker</param>
+        /// <returns>PUBACK message instance</returns>
+        public static MqttMsgPuback Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPuback msg = new MqttMsgPuback();
+
+            // 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
+        }
+    }
+}

+ 128 - 0
M2Mqtt/Messages/MqttMsgPubcomp.cs

@@ -0,0 +1,128 @@
+/*
+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.Messages
+{
+    /// <summary>
+    /// Class for PUBCOMP message from broker to client
+    /// </summary>
+    public class MqttMsgPubcomp : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier for the acknowledged publish message
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        private ushort messageId;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPubcomp()
+        {
+            this.type = MQTT_MSG_PUBCOMP_TYPE;
+        }
+
+        public override byte[] GetBytes()
+        {
+            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
+            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="channel">Channel connected to the broker</param>
+        /// <returns>PUBCOMP message instance</returns>
+        public static MqttMsgPubcomp Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPubcomp msg = new MqttMsgPubcomp();
+
+            // 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
+        }
+    }
+}

+ 280 - 0
M2Mqtt/Messages/MqttMsgPublish.cs

@@ -0,0 +1,280 @@
+/*
+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; }
+        }
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message topic
+        private string topic;
+        // message data
+        private byte[] message;
+        // message identifier
+        ushort messageId;
+
+        /// <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()
+        {
+            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);
+
+            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="channel">Channel connected to the broker</param>
+        /// <returns>PUBLISH message instance</returns>
+        public static MqttMsgPublish Parse(byte fixedHeaderFirstByte, 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);
+            // 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;
+        }
+    }
+}

+ 55 - 0
M2Mqtt/Messages/MqttMsgPublishedEventArgs.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 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; }
+        }
+
+        #endregion
+
+        // message identifier
+        ushort messageId;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="messageId">Message identifier published</param>
+        public MqttMsgPublishedEventArgs(ushort messageId)
+        {
+            this.messageId = messageId;
+        }
+    }
+}

+ 128 - 0
M2Mqtt/Messages/MqttMsgPubrec.cs

@@ -0,0 +1,128 @@
+/*
+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.Messages
+{
+    /// <summary>
+    /// Class for PUBREC message from broker to client
+    /// </summary>
+    public class MqttMsgPubrec : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier for the acknowledged publish message
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        private ushort messageId;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPubrec()
+        {
+            this.type = MQTT_MSG_PUBREC_TYPE;
+        }
+
+        public override byte[] GetBytes()
+        {
+            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
+            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="channel">Channel connected to the broker</param>
+        /// <returns>PUBREC message instance</returns>
+        public static MqttMsgPubrec Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPubrec msg = new MqttMsgPubrec();
+
+            // 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
+        }
+    }
+}

+ 138 - 0
M2Mqtt/Messages/MqttMsgPubrel.cs

@@ -0,0 +1,138 @@
+/*
+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.Messages
+{
+    /// <summary>
+    /// Class for PUBREL message from client top broker
+    /// </summary>
+    public class MqttMsgPubrel : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier for the acknowledged publish message
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        private ushort messageId;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPubrel()
+        {
+            this.type = MQTT_MSG_PUBREL_TYPE;
+            // PUBREL message use QoS Level 1
+            this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
+        }
+
+        public override byte[] GetBytes()
+        {
+            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
+            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="channel">Channel connected to the broker</param>
+        /// <returns>PUBREL message instance</returns>
+        public static MqttMsgPubrel Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPubrel msg = new MqttMsgPubrel();
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // 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
+        }
+    }
+}

+ 163 - 0
M2Mqtt/Messages/MqttMsgSuback.cs

@@ -0,0 +1,163 @@
+/*
+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.Messages
+{
+    /// <summary>
+    /// Class for SUBACK message from broker to client
+    /// </summary>
+    public class MqttMsgSuback : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier for the subscribe message
+        /// that is acknowledged
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        /// <summary>
+        /// List of granted QOS Levels
+        /// </summary>
+        public byte[] GrantedQoSLevels
+        {
+            get { return this.grantedQosLevels; }
+            set { this.grantedQosLevels = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        private ushort messageId;
+        // 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="channel">Channel connected to the broker</param>
+        /// <returns>SUBACK message instance</returns>
+        public static MqttMsgSuback Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgSuback msg = new MqttMsgSuback();
+
+            // 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()
+        {
+            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
+            buffer[index] = (byte)(MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET);
+            index++;
+
+            // 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
+        }
+    }
+}

+ 265 - 0
M2Mqtt/Messages/MqttMsgSubscribe.cs

@@ -0,0 +1,265 @@
+/*
+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; }
+        }
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // topics to subscribe
+        string[] topics;
+        // QOS levels related to topics
+        byte[] qosLevels;
+        // message identifier
+        ushort messageId;
+
+        /// <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
+            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="channel">Channel connected to the broker</param>
+        /// <returns>SUBSCRIBE message instance</returns>
+        public static MqttMsgSubscribe Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            byte[] topicUtf8;
+            int topicUtf8Length;
+            MqttMsgSubscribe msg = new MqttMsgSubscribe();
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            int received = channel.Receive(buffer);
+
+            // 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()
+        {
+            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
+            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;
+        }
+    }
+}

+ 132 - 0
M2Mqtt/Messages/MqttMsgUnsuback.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.Messages
+{
+    /// <summary>
+    /// Class for UNSUBACK message from broker to client
+    /// </summary>
+    public class MqttMsgUnsuback : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier for the unsubscribe message
+        /// that is acknowledged
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        private ushort messageId;
+        
+        /// <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="channel">Channel connected to the broker</param>
+        /// <returns>UNSUBACK message instance</returns>
+        public static MqttMsgUnsuback Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgUnsuback msg = new MqttMsgUnsuback();
+
+            // 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()
+        {
+            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
+            buffer[index] = (byte)(MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET);
+            index++;
+
+            // 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
+        }
+    }
+}

+ 232 - 0
M2Mqtt/Messages/MqttMsgUnsubscribe.cs

@@ -0,0 +1,232 @@
+/*
+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; }
+        }
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // topics to unsubscribe
+        string[] topics;
+        // message identifier
+        ushort messageId;
+
+        /// <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
+            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="channel">Channel connected to the broker</param>
+        /// <returns>UNSUBSCRIBE message instance</returns>
+        public static MqttMsgUnsubscribe Parse(byte fixedHeaderFirstByte, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            byte[] topicUtf8;
+            int topicUtf8Length;
+            MqttMsgUnsubscribe msg = new MqttMsgUnsubscribe();
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            int received = channel.Receive(buffer);
+
+            // 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()
+        {
+            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
+            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;
+        }
+    }
+}

+ 2140 - 0
M2Mqtt/MqttClient.cs

@@ -0,0 +1,2140 @@
+/*
+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.Utility;
+// 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 = "ReceiveEventThread";
+        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);
+#endif
+
+        /// <summary>
+        /// Delegate that defines event handler for client disconnection (DISCONNECT message or not)
+        /// </summary>
+        public delegate void MqttMsgDisconnectEventHandler(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;
+        // keep alive timeout expired
+        private bool isKeepAliveTimeout;
+        // last communication time in ticks
+        private long 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;
+#endif
+        // event for client disconnection (DISCONNECT message or not)
+        public event MqttMsgDisconnectEventHandler MqttMsgDisconnected;
+        
+        // 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;
+        // receive queue for received messages
+        private Queue receiveQueue;
+
+        // reference to avoid access to singleton via property
+        private MqttSettings settings;
+
+        // current message identifier generated
+        private ushort messageIdCounter = 0;
+
+        /// <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; }
+
+#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)
+        {
+        }
+
+        /// <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>
+        [Obsolete("Use this ctor MqttClient(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert) insted")]
+        public MqttClient(IPAddress brokerIpAddress, int brokerPort, bool secure, X509Certificate caCert)
+        {
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            this.Init(brokerIpAddress.ToString(), brokerPort, secure, caCert, null, null);
+#else
+            this.Init(brokerIpAddress.ToString(), brokerPort, secure, caCert);
+#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)
+#else
+            this(brokerHostName, MqttSettings.MQTT_BROKER_DEFAULT_PORT, false)
+#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>
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP)
+        /// <param name="caCert">CA certificate for secure connection</param>
+        public MqttClient(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert)            
+#else
+        public MqttClient(string brokerHostName, int brokerPort, bool secure)            
+#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, null, null);
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP)
+            this.Init(brokerHostName, brokerPort, secure);
+#else
+            this.Init(brokerHostName, brokerPort, secure, caCert);
+#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="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, 
+            RemoteCertificateValidationCallback userCertificateValidationCallback)
+            : this(brokerHostName, brokerPort, secure, caCert, 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="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, 
+            RemoteCertificateValidationCallback userCertificateValidationCallback, 
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+            : this(brokerHostName, brokerPort, secure, null, 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="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,
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+        {
+            this.Init(brokerHostName, brokerPort, secure, caCert, userCertificateValidationCallback, userCertificateSelectionCallback);
+        }
+#endif
+
+#if BROKER
+        #if !(WINDOWS_APP || WINDOWS_PHONE_APP)
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="socket">Raw socket for communication</param>
+        public MqttClient(Socket socket)
+#else
+        public MqttClient(StreamSocket socket)
+#endif
+        {
+            this.channel = new MqttNetworkChannel(socket);
+
+            // 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.receiveQueue = new Queue();
+            this.internalQueue = new Queue();
+        }
+#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>
+#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, 
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP)
+        private void Init(string brokerHostName, int brokerPort, bool secure)
+#else
+        private void Init(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert)
+#endif
+        {
+#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;
+
+            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.receiveQueue = new Queue();
+            this.internalQueue = new Queue();
+
+            // 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, userCertificateValidationCallback, userCertificateSelectionCallback);
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP)
+            this.channel = new MqttNetworkChannel(this.brokerHostName, this.brokerPort, secure);
+#else
+            this.channel = new MqttNetworkChannel(this.brokerHostName, this.brokerPort, secure, caCert);
+#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);
+
+            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;
+            // 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
+
+                // 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.ReceiveEventThread);
+                
+                // 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.Close();
+        }
+
+#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.ReceiveEventThread);
+
+            // 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 thread
+            //if (this.receiveThread != null)
+            //    this.receiveThread.Join();
+
+            // wait end receive event thread
+            if (this.receiveEventWaitHandle != null)
+            {
+                this.receiveEventWaitHandle.Set();
+                // NOTE : no join because Close() could be called inside ReceiveEventThread
+                //        so we have to avoid deadlock
+                //this.receiveEventThread.Join();
+            }
+
+            // wait end process inflight thread
+            if (this.inflightWaitHandle != null)
+            {
+                this.inflightWaitHandle.Set();
+                // NOTE : no join because Close() could be called inside ProcessInflightThread
+                //        so we have to avoid deadlock
+                //this.processInflightThread.Join();
+            }
+
+            // avoid deadlock if keep alive timeout expired
+            if (!this.isKeepAliveTimeout)
+            {
+#if BROKER
+                // unlock keep alive thread and wait
+                //if (this.keepAliveThread != null)
+                    this.keepAliveEvent.Set();
+#else
+                // unlock keep alive thread and wait
+                this.keepAliveEvent.Set();
+
+                if (this.keepAliveEventEnd != null)
+                    this.keepAliveEventEnd.WaitOne();
+#endif
+            }
+
+            // close network channel
+            this.channel.Close();
+
+            // keep alive thread will set it gracefully
+            if (!this.isKeepAliveTimeout)
+                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
+
+                this.isKeepAliveTimeout = true;
+                // client must close connection
+                this.Close();
+                return null;
+            }
+        }
+
+#if BROKER
+        /// <summary>
+        /// Send CONNACK message to the client (connection accepted or not)
+        /// </summary>
+        /// <param name="returnCode">Return code for CONNACK message</param>
+        /// <param name="connect">CONNECT message with all client information</param>
+        public void Connack(byte returnCode, MqttMsgConnect connect)
+        {
+            this.lastCommTime = 0;
+
+            // create CONNACK message and ...
+            MqttMsgConnack connack = new MqttMsgConnack();
+            connack.ReturnCode = returnCode;
+            // ... send it to the client
+            this.Send(connack);
+
+            // connection accepted, start keep alive thread checking
+            if (connack.ReturnCode == MqttMsgConnack.CONN_ACCEPTED)
+            {
+                this.ClientId = connect.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.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
+            this.EnqueueInflight(publish, MqttMsgFlow.ToPublish);           
+
+            return publish.MessageId;
+        }
+
+        /// <summary>
+        /// Wrapper method for raising message received event
+        /// </summary>
+        /// <param name="msg">Message received</param>
+        private void OnMqttMsgReceived(MqttMsgBase msg)
+        {
+            lock (this.receiveQueue)
+            {
+                this.receiveQueue.Enqueue(msg);
+            }
+
+            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>
+        private void OnMqttMsgPublished(ushort messageId)
+        {
+            if (this.MqttMsgPublished != null)
+            {
+                this.MqttMsgPublished(this,
+                    new MqttMsgPublishedEventArgs(messageId));
+            }
+        }
+
+        /// <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 client connection event
+        /// </summary>
+        private void OnMqttMsgConnected(MqttMsgConnect connect)
+        {
+            if (this.MqttMsgConnected != null)
+            {
+                this.MqttMsgConnected(this, new MqttMsgConnectEventArgs(connect));
+            }
+        }
+#endif
+
+        /// <summary>
+        /// Wrapper method for client disconnection event
+        /// </summary>
+        private void OnMqttMsgDisconnected()
+        {
+            if (this.MqttMsgDisconnected != null)
+            {
+                this.MqttMsgDisconnected(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());
+        }
+
+        /// <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(), 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>
+        private void 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(((MqttMsgPublish)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;
+                }
+
+                // queue message context
+                MqttMsgContext msgContext = new MqttMsgContext()
+                {
+                    Message = msg,
+                    State = state,
+                    Flow = flow,
+                    Attempt = 0
+                };
+
+                lock (this.inflightQueue)
+                {
+                    // enqueue message and unlock send thread
+                    this.inflightQueue.Enqueue(msgContext);
+                }
+            }
+
+            this.inflightWaitHandle.Set();
+        }
+
+        /// <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(((MqttMsgPubrel)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 = ((MqttMsgPubrel)msg).MessageId;
+
+                        this.Send(pubcomp);
+
+                        enqueue = false;
+                    }
+                }
+            }
+
+            if (enqueue)
+            {
+                lock (this.internalQueue)
+                {
+                    this.internalQueue.Enqueue(msg);
+                    this.inflightWaitHandle.Set();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Thread for receiving messages
+        /// </summary>
+        private void ReceiveThread()
+        {
+            int readBytes = 0;
+            byte[] fixedHeaderFirstByte = new byte[1];
+            byte msgType;
+            
+#if BROKER
+            long now = 0;
+
+            // receive thread started, broker need to receive the first message
+            // (CONNECT) within a reasonable amount of time after TCP/IP connection 
+            long connectTime = Environment.TickCount;
+#endif
+
+            while (this.isRunning)
+            {
+                try
+                {
+                    if (this.channel.DataAvailable)
+                        // read first byte (fixed header)
+                        readBytes = this.channel.Receive(fixedHeaderFirstByte);
+                    else
+                    {
+#if BROKER
+                        // client not connected (client didn't send CONNECT yet)
+                        if (!this.IsConnected)
+                        {
+                            now = Environment.TickCount;
+
+                            // if connect timeout exceeded ... 
+                            if ((now - connectTime) >= this.settings.TimeoutOnConnection)
+                            {
+                                // client must close connection
+                                this.Close();
+
+                                // client raw disconnection
+                                this.OnMqttMsgDisconnected();
+                            }
+                        }
+#endif
+                        // no bytes available, sleep before retry
+                        readBytes = 0;
+                        Fx.SleepThread(10);
+                    }
+
+                    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], this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", connect);
+#endif
+
+                                // raise message received event
+                                this.OnMqttMsgReceived(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], 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], this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", this.msgReceived);
+#endif
+
+                                MqttMsgPingResp pingresp = new MqttMsgPingResp();
+                                this.Send(pingresp);
+
+                                // raise message received event
+                                //this.OnMqttMsgReceived(this.msgReceived);
+                                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], 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], this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", subscribe);
+#endif
+
+                                // raise message received event
+                                this.OnMqttMsgReceived(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], 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], 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], 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], 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], 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], 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], this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", unsubscribe);
+#endif
+
+                                // raise message received event
+                                this.OnMqttMsgReceived(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], 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], this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", disconnect);
+#endif
+
+                                // raise message received event
+                                this.OnMqttMsgReceived(disconnect);
+
+                                break;
+#else
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                            default:
+
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+                        }
+
+                        this.exReceiving = null;
+                    }
+
+                }
+                catch (Exception e)
+                {
+#if TRACE
+                    MqttUtility.Trace.WriteLine(TraceLevel.Error, "Exception occurred: {0}", e.ToString());
+#endif
+                    this.exReceiving = new MqttCommunicationException(e);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Thread for handling keep alive message
+        /// </summary>
+        private void KeepAliveThread()
+        {
+            long now = 0;
+            int wait = this.keepAlivePeriod;
+            this.isKeepAliveTimeout = false;
+
+            // 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)
+                {
+                    now = Environment.TickCount;
+
+                    // if timeout exceeded ...
+                    if ((now - this.lastCommTime) >= this.keepAlivePeriod)
+                    {
+#if BROKER
+                        this.isKeepAliveTimeout = true;
+                        // client must close connection
+                        this.Close();
+#else
+                        // ... send keep alive
+						this.Ping();
+						wait = this.keepAlivePeriod;
+#endif
+                    }
+                    else
+                    {
+                        // update waiting time
+                        wait = (int)(this.keepAlivePeriod - (now - this.lastCommTime));
+                    }
+                }
+            }
+
+            if (this.isKeepAliveTimeout)
+            {
+                this.IsConnected = false;
+                // raise disconnection client event
+                this.OnMqttMsgDisconnected();
+            }
+
+            // signal thread end
+            this.keepAliveEventEnd.Set();
+        }
+
+        /// <summary>
+        /// Thread for raising received message event
+        /// </summary>
+        private void ReceiveEventThread()
+        {
+            while (this.isRunning)
+            {
+                if (this.receiveQueue.Count == 0)
+                    // wait on receiving message from client
+                    this.receiveEventWaitHandle.WaitOne();
+
+                // check if it is running or we are closing client
+                if (this.isRunning)
+                {
+                    // get message from queue
+                    MqttMsgBase msg = null;
+                    lock (this.receiveQueue)
+                    {
+                        if (this.receiveQueue.Count > 0)
+                            msg = (MqttMsgBase)this.receiveQueue.Dequeue();
+                    }
+
+                    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:
+
+                                // 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(((MqttMsgPuback)msg).MessageId);
+                                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(((MqttMsgPubcomp)msg).MessageId);
+                                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(((MqttMsgUnsuback)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
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Process inflight messages queue
+        /// </summary>
+        private void ProcessInflightThread()
+        {
+            MqttMsgContext msgContext = null;
+            MqttMsgBase msgInflight = null;
+            MqttMsgBase msgReceived = null;
+            bool acknowledge = false;
+            int timeout = Timeout.Infinite;
+
+            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)
+                        {
+                            // 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;
+
+                                // 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)
+                                        {
+                                            // notify published message from broker (no need acknowledged)
+                                            this.OnMqttMsgReceived(msgInflight);
+                                        }
+                                        break;
+
+                                    case MqttMsgState.QueuedQos1:
+
+                                        // QoS 1, PUBLISH or SUBSCRIBE/UNSUBSCRIBE message to send to broker, state change to wait PUBACK or SUBACK/UNSUBACK
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            if (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE)
+                                                // PUBLISH message to send, wait for PUBACK
+                                                msgContext.State = MqttMsgState.WaitForPuback;
+                                            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;
+
+                                            msgContext.Timestamp = Environment.TickCount;
+                                            msgContext.Attempt++;
+                                            // retry ? set dup flag
+                                            if (msgContext.Attempt > 1)
+                                                msgInflight.DupFlag = true;
+
+                                            this.Send(msgInflight);
+
+                                            // update timeout
+                                            int msgTimeout = (this.settings.DelayOnRetry - (Environment.TickCount - msgContext.Timestamp));
+                                            timeout = (msgTimeout < timeout) ? msgTimeout : 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 = ((MqttMsgPublish)msgInflight).MessageId;
+
+                                            this.Send(puback);
+
+                                            // notify published message from broker and acknowledged
+                                            this.OnMqttMsgReceived(msgInflight);
+                                        }
+                                        break;
+
+                                    case MqttMsgState.QueuedQos2:
+
+                                        // QoS 2, PUBLISH message to send to broker, state change to wait PUBREC
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            msgContext.State = MqttMsgState.WaitForPubrec;
+                                            msgContext.Timestamp = Environment.TickCount;
+                                            msgContext.Attempt++;
+                                            // retry ? set dup flag
+                                            if (msgContext.Attempt > 1)
+                                                msgInflight.DupFlag = true;
+
+                                            this.Send(msgInflight);
+
+                                            // update timeout
+                                            int msgTimeout = (this.settings.DelayOnRetry - (Environment.TickCount - msgContext.Timestamp));
+                                            timeout = (msgTimeout < timeout) ? msgTimeout : 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 = ((MqttMsgPublish)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) && (((MqttMsgPuback)msgReceived).MessageId == ((MqttMsgPublish)msgInflight).MessageId)) ||
+                                                    ((msgReceived.Type == MqttMsgBase.MQTT_MSG_SUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE) && (((MqttMsgSuback)msgReceived).MessageId == ((MqttMsgSubscribe)msgInflight).MessageId)) ||
+                                                    ((msgReceived.Type == MqttMsgBase.MQTT_MSG_UNSUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE) && (((MqttMsgUnsuback)msgReceived).MessageId == ((MqttMsgUnsubscribe)msgInflight).MessageId)))
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                    }
+
+                                                    // notify received acknowledge from broker of a published message or subscribe/unsubscribe message
+                                                    this.OnMqttMsgReceived(msgReceived);
+                                                }
+                                            }
+
+                                            // current message not acknowledged, no PUBACK or SUBACK/UNSUBACK or not equal messageid 
+                                            if (!acknowledge)
+                                            {
+                                                // 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 ((Environment.TickCount - msgContext.Timestamp) >= 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
+                                                {
+                                                    // 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 - (Environment.TickCount - msgContext.Timestamp));
+                                                    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 (((MqttMsgPubrec)msgReceived).MessageId == ((MqttMsgPublish)msgInflight).MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                    }
+
+                                                    MqttMsgPubrel pubrel = new MqttMsgPubrel();
+                                                    pubrel.MessageId = ((MqttMsgPublish)msgInflight).MessageId;
+
+                                                    msgContext.State = MqttMsgState.WaitForPubcomp;
+                                                    msgContext.Timestamp = Environment.TickCount;
+                                                    msgContext.Attempt = 1;
+
+                                                    this.Send(pubrel);
+
+                                                    // update timeout
+                                                    int msgTimeout = (this.settings.DelayOnRetry - (Environment.TickCount - msgContext.Timestamp));
+                                                    timeout = (msgTimeout < timeout) ? msgTimeout : timeout;
+
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+                                                }
+                                            }
+
+                                            // current message not acknowledged
+                                            if (!acknowledge)
+                                            {
+                                                // check timeout for receiving PUBREC since PUBLISH was sent
+                                                if ((Environment.TickCount - msgContext.Timestamp) >= 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
+                                                {
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+
+                                                    // update timeout
+                                                    int msgTimeout = (this.settings.DelayOnRetry - (Environment.TickCount - msgContext.Timestamp));
+                                                    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 (((MqttMsgPubrel)msgReceived).MessageId == ((MqttMsgPublish)msgInflight).MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                    }
+
+                                                    MqttMsgPubcomp pubcomp = new MqttMsgPubcomp();
+                                                    pubcomp.MessageId = ((MqttMsgPublish)msgInflight).MessageId;
+
+                                                    this.Send(pubcomp);
+
+                                                    // notify published message from broker and acknowledged
+                                                    this.OnMqttMsgReceived(msgInflight);
+                                                }
+                                                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 (((MqttMsgPubcomp)msgReceived).MessageId == ((MqttMsgPublish)msgInflight).MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                    }
+
+                                                    // notify received acknowledge from broker of a published message
+                                                    this.OnMqttMsgReceived(msgReceived);
+                                                }
+                                            }
+
+                                            // current message not acknowledged
+                                            if (!acknowledge)
+                                            {
+                                                // check timeout for receiving PUBCOMP since PUBREL was sent
+                                                if ((Environment.TickCount - msgContext.Timestamp) >= 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
+                                                {
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+
+                                                    // update timeout
+                                                    int msgTimeout = (this.settings.DelayOnRetry - (Environment.TickCount - msgContext.Timestamp));
+                                                    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 = ((MqttMsgPublish)msgInflight).MessageId;
+
+                                            msgContext.State = MqttMsgState.WaitForPubcomp;
+                                            msgContext.Timestamp = Environment.TickCount;
+                                            msgContext.Attempt++;
+                                            // retry ? set dup flag
+                                            if (msgContext.Attempt > 1)
+                                                pubrel.DupFlag = true;
+
+                                            this.Send(pubrel);
+
+                                            // update timeout
+                                            int msgTimeout = (this.settings.DelayOnRetry - (Environment.TickCount - msgContext.Timestamp));
+                                            timeout = (msgTimeout < timeout) ? msgTimeout : 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;
+                        }
+                    }
+                }
+            }
+            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
+
+                this.Close();
+
+                // raise disconnection client event
+                this.OnMqttMsgDisconnected();
+            }
+        }
+
+        /// <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) &&
+                        (((MqttMsgPublish)msgCtx.Message).MessageId == this.MessageId) &&
+                        msgCtx.Flow == this.Flow);
+
+            }
+        }
+    }
+}

+ 96 - 0
M2Mqtt/MqttSettings.cs

@@ -0,0 +1,96 @@
+/*
+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 = 5000;
+        // 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 = 5000;
+
+        /// <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>
+        /// 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;
+        }
+    }
+}

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

+ 320 - 0
M2Mqtt/Net/MqttNetworkChannel.cs

@@ -0,0 +1,320 @@
+/*
+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
+        private X509Certificate caCert;
+
+        /// <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)
+        {
+            this.socket = socket;
+        }
+
+        /// <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, null)
+#else
+            : this(remoteHostName, remotePort, false, null)
+#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>
+#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,
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+#else
+        public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, X509Certificate caCert)
+#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;
+#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,
+                    null,
+                    new X509Certificate[] { this.caCert },
+                    SslVerification.CertificateRequired,
+                    SslProtocols.TLSv1);
+#else
+                      this.sslStream.AuthenticateAsClient(
+                        this.remoteHostName,
+                        null,
+                        SslProtocols.Tls,
+                        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);
+                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;
+                while (idx < buffer.Length)
+                {
+                    idx += this.sslStream.Read(buffer, idx, buffer.Length - idx);
+                }
+                return buffer.Length;
+            }
+            else
+            {
+                // read all data needed (until fill buffer)
+                int idx = 0;
+                while (idx < buffer.Length)
+                {
+                    idx += this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None);
+                }
+                return buffer.Length;
+            }
+#else
+            // read all data needed (until fill buffer)
+            int idx = 0;
+            while (idx < buffer.Length)
+            {
+                idx += this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None);
+            }
+            return buffer.Length;
+#endif
+        }
+
+        /// <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>
+    /// 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
+        }
+    }
+}

+ 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("3.6.0.0")]
+// to avoid compilation error (AssemblyFileVersionAttribute doesn't exist) under .Net CF 3.5
+#if !WindowsCE
+[assembly: AssemblyFileVersion("3.6.0.0")]
+#endif

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

+ 85 - 0
M2Mqtt/Utility/Trace.cs

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

+ 106 - 0
M2Mqtt/WinRT/MqttNetworkChannel.cs

@@ -0,0 +1,106 @@
+/*
+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;
+
+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;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="socket">Socket opened with the client</param>
+        public MqttNetworkChannel(StreamSocket socket)
+        {
+            this.socket = socket;
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="remoteHostName">Remote Host name</param>
+        /// <param name="remotePort">Remote port</param>
+        /// <param name="secure">Using SSL</param>
+        public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure)
+        {
+            this.remoteHostName = new HostName(remoteHostName);
+            this.remotePort = remotePort;
+            this.secure = secure;
+        }
+
+        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)
+            {
+                // read is executed synchronously
+                result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask().Result;
+                idx += (int)result.Length;
+            }
+            return buffer.Length;
+        }
+
+        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(),
+                this.secure ? SocketProtectionLevel.Tls12 : SocketProtectionLevel.PlainSocket).AsTask().Wait();
+        }
+
+        
+    }
+}

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

+ 77 - 0
M2Mqtt/uM2MqttNetMf42.csproj

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <AssemblyName>M2Mqtt</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\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\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="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="MqttSettings.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility\Trace.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>

+ 77 - 0
M2Mqtt/uM2MqttNetMf43.csproj

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <AssemblyName>M2Mqtt</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\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\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="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="MqttSettings.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="Utility\Trace.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>

+ 20 - 0
M2MqttMono.sln

@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2MqttMono", "M2Mqtt\M2MqttMono.csproj", "{9B706DEC-4CE7-4764-BDBE-8A5F855E5857}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9B706DEC-4CE7-4764-BDBE-8A5F855E5857}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9B706DEC-4CE7-4764-BDBE-8A5F855E5857}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9B706DEC-4CE7-4764-BDBE-8A5F855E5857}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9B706DEC-4CE7-4764-BDBE-8A5F855E5857}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		StartupItem = M2Mqtt\M2MqttMono.csproj
+	EndGlobalSection
+EndGlobal

+ 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}") = "M2MqttNetCf35", "M2Mqtt\M2MqttNetCf35.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

+ 29 - 0
M2MqttVS2010.sln

@@ -0,0 +1,29 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "uM2Mqtt", "M2Mqtt\uM2MqttNetMf42.csproj", "{F733523A-F14E-4F5A-9E7C-085CA80F52B1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt", "M2Mqtt\M2Mqtt.csproj", "{A11AEF5A-B246-4FE8-8330-06DB73CC8074}"
+EndProject
+Global
+	GlobalSection(TestCaseManagementSettings) = postSolution
+		CategoryFile = M2Mqtt.vsmdi
+	EndGlobalSection
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{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
+		{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
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 38 - 0
M2MqttVS2012.sln

@@ -0,0 +1,38 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "uM2MqttNetMf43", "M2Mqtt\uM2MqttNetMf43.csproj", "{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "uM2MqttNetMf42", "M2Mqtt\uM2MqttNetMf42.csproj", "{F733523A-F14E-4F5A-9E7C-085CA80F52B1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt", "M2Mqtt\M2Mqtt.csproj", "{A11AEF5A-B246-4FE8-8330-06DB73CC8074}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2MqttNetCf39", "M2Mqtt\M2MqttNetCf39.csproj", "{BB9B7FF4-6502-41AF-8851-5060B67645E8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{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
+		{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
+		{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 28 - 0
M2MqttVS2013.sln

@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30501.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt", "M2Mqtt\M2Mqtt.csproj", "{A11AEF5A-B246-4FE8-8330-06DB73CC8074}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2MqttWinRT", "M2Mqtt\M2MqttWinRT.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
+		{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