Compare commits

...
4 Commits
Author SHA1 Message Date
Christian Kratky 105abeba06 * [Server] Added support for complex client IDs.
* [Server] Fixed an issue with not correctly removed old client sessions.
* [Server] Several minor performance improvements.
* [Server] An existing client session is no longer closed if a new client connection is invalid.
* [Client] Added support for sending "CleanSession" flag.
2017-05-05 21:34:37 +02:00
Christian Kratky b3a6919ea0 Add support for complex device IDs. 2017-04-30 19:32:52 +02:00
Christian Kratky 9816f12df6 Performance optimizations 2017-04-09 15:10:35 +02:00
Christian Kratky 8bfad437cf Add nuget support 2017-04-01 21:51:36 +02:00
39 changed files with 946 additions and 592 deletions
+2 -1
View File
@@ -242,4 +242,5 @@ ModelManifest.xml
.paket/paket.exe .paket/paket.exe
# FAKE - F# Make # FAKE - F# Make
.fake/ .fake/
nuget.exe
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<Authors>Christian Kratky</Authors>
<Company>Christian Kratky</Company>
<Product>MQTTnet</Product>
<Description>MQTTnet for .NET Core</Description>
<Copyright>Copyright © Christian Kratky 2016-2017</Copyright>
<Version>2.0.4.0</Version>
<AssemblyVersion>2.0.4.0</AssemblyVersion>
<FileVersion>2.0.4.0</FileVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<AssemblyName>MQTTnet</AssemblyName>
<RootNamespace>MQTTnet</RootNamespace>
<PackageId>MQTTnet</PackageId>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<Authors>Christian Kratky</Authors>
<Company>Christian Kratky</Company>
<Product>MQTTnet</Product>
<Description>MQTTnet is a .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).</Description>
<Copyright>Copyright © Christian Kratky 2016-2017</Copyright>
<Version>2.1.1.0</Version>
<AssemblyVersion>2.1.1.0</AssemblyVersion>
<FileVersion>2.1.1.0</FileVersion>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<AssemblyName>MQTTnet</AssemblyName>
<RootNamespace>MQTTnet</RootNamespace>
<PackageId>MQTTnet.NetCore</PackageId>
<PackageProjectUrl>https://github.com/chkr1011/MQTTnet</PackageProjectUrl>
<RepositoryUrl>https://github.com/chkr1011/MQTTnet</RepositoryUrl>
<PackageTags>MQTT MQTTClient MQTTServer MQTTBroker Broker</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</PackageIconUrl>
<PackageLicenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</PackageLicenseUrl>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Any CPU|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Any CPU|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Any CPU|x86'" />
<ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" />
</ItemGroup>
</Project>
@@ -32,6 +32,69 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|AnyCPU'">
<OutputPath>bin\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x86'">
<OutputPath>bin\x86\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x64'">
<OutputPath>bin\x64\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -45,7 +108,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj"> <ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project> <Project>{2ecb99e4-72d0-4c23-99ba-93d511d3967d}</Project>
<Name>MQTTnet.Core</Name> <Name>MQTTnet.Core</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: Guid("a480ef90-0eaa-4d9a-b271-47a9c47f6f7d")] [assembly: Guid("a480ef90-0eaa-4d9a-b271-47a9c47f6f7d")]
[assembly: AssemblyVersion("2.1.0.4")] [assembly: AssemblyVersion("2.1.1.0")]
[assembly: AssemblyFileVersion("2.1.0.4")] [assembly: AssemblyFileVersion("2.1.1.0")]
@@ -57,6 +57,7 @@
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<DocumentationFile>bin\x86\Release\MQTTnet.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget>ARM</PlatformTarget> <PlatformTarget>ARM</PlatformTarget>
@@ -79,6 +80,7 @@
<PlatformTarget>ARM</PlatformTarget> <PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<DocumentationFile>bin\ARM\Release\MQTTnet.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
@@ -101,6 +103,8 @@
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<GenerateLibraryLayout>false</GenerateLibraryLayout>
<DocumentationFile>bin\x64\Release\MQTTnet.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included --> <!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
@@ -116,13 +120,63 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj"> <ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project> <Project>{2ecb99e4-72d0-4c23-99ba-93d511d3967d}</Project>
<Name>MQTTnet.Core</Name> <Name>MQTTnet.Core</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion> <VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|AnyCPU'">
<OutputPath>bin\Any CPU\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoStdLib>true</NoStdLib>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x86'">
<OutputPath>bin\x86\Any CPU\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DocumentationFile>bin\x86\Release\MQTTnet.XML</DocumentationFile>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<NoStdLib>true</NoStdLib>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|ARM'">
<OutputPath>bin\ARM\Any CPU\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DocumentationFile>bin\ARM\Release\MQTTnet.XML</DocumentationFile>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<NoStdLib>true</NoStdLib>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x64'">
<OutputPath>bin\x64\Any CPU\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DocumentationFile>bin\x64\Release\MQTTnet.XML</DocumentationFile>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<NoStdLib>true</NoStdLib>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
@@ -10,5 +10,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: AssemblyVersion("2.1.0.4")] [assembly: AssemblyVersion("2.1.1.0")]
[assembly: AssemblyFileVersion("2.1.0.4")] [assembly: AssemblyFileVersion("2.1.1.0")]
@@ -1,33 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
This file contains Runtime Directives, specifications about types your application accesses
through reflection and other dynamic code patterns. Runtime Directives are used to control the
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
library does not do any reflection, then you generally do not need to edit this file. However,
if your library reflects over types, especially types passed to it or derived from its types,
then you should write Runtime Directives.
The most common use of reflection in libraries is to discover information about types passed
to the library. Runtime Directives have three ways to express requirements on types passed to
your library.
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
Use these directives to reflect over types passed as a parameter.
2. SubTypes
Use a SubTypes directive to reflect over types derived from another type.
3. AttributeImplies
Use an AttributeImplies directive to indicate that your library needs to reflect over
types or methods decorated with an attribute.
For more information on writing Runtime Directives for libraries, please visit
http://go.microsoft.com/fwlink/?LinkID=391919
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata"> <Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="MQTTnet.Universal"> <Library Name="MQTTnet.Universal">
<!-- add directives for your library here -->
</Library> </Library>
</Directives> </Directives>
@@ -3,7 +3,8 @@
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0" "Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0"
}, },
"frameworks": { "frameworks": {
"uap10.0": {} "uap10.0": {},
"netstandard1.1": {}
}, },
"runtimes": { "runtimes": {
"win10-arm": {}, "win10-arm": {},
+17 -20
View File
@@ -53,6 +53,7 @@ namespace MQTTnet.Core.Client
ClientId = _options.ClientId, ClientId = _options.ClientId,
Username = _options.UserName, Username = _options.UserName,
Password = _options.Password, Password = _options.Password,
CleanSession = _options.CleanSession,
KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds, KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
WillMessage = willApplicationMessage WillMessage = willApplicationMessage
}; };
@@ -66,7 +67,7 @@ namespace MQTTnet.Core.Client
_packetDispatcher.Reset(); _packetDispatcher.Reset();
IsConnected = true; IsConnected = true;
Task.Run(async () => await ReceivePackets(_cancellationTokenSource.Token), _cancellationTokenSource.Token).Forget(); Task.Run(() => ReceivePackets(_cancellationTokenSource.Token), _cancellationTokenSource.Token).Forget();
var response = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket); var response = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket);
if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted) if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
@@ -76,7 +77,7 @@ namespace MQTTnet.Core.Client
if (_options.KeepAlivePeriod != TimeSpan.Zero) if (_options.KeepAlivePeriod != TimeSpan.Zero)
{ {
Task.Run(async () => await SendKeepAliveMessagesAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token).Forget(); Task.Run(() => SendKeepAliveMessagesAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token).Forget();
} }
Connected?.Invoke(this, EventArgs.Empty); Connected?.Invoke(this, EventArgs.Empty);
@@ -88,11 +89,11 @@ namespace MQTTnet.Core.Client
await DisconnectInternalAsync(); await DisconnectInternalAsync();
} }
public async Task<IList<MqttSubscribeResult>> SubscribeAsync(params TopicFilter[] topicFilters) public Task<IList<MqttSubscribeResult>> SubscribeAsync(params TopicFilter[] topicFilters)
{ {
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
return await SubscribeAsync(topicFilters.ToList()); return SubscribeAsync(topicFilters.ToList());
} }
public async Task<IList<MqttSubscribeResult>> SubscribeAsync(IList<TopicFilter> topicFilters) public async Task<IList<MqttSubscribeResult>> SubscribeAsync(IList<TopicFilter> topicFilters)
@@ -114,20 +115,14 @@ namespace MQTTnet.Core.Client
throw new MqttProtocolViolationException("The return codes are not matching the topic filters [MQTT-3.9.3-1]."); throw new MqttProtocolViolationException("The return codes are not matching the topic filters [MQTT-3.9.3-1].");
} }
var result = new List<MqttSubscribeResult>(); return topicFilters.Select((t, i) => new MqttSubscribeResult(t, response.SubscribeReturnCodes[i])).ToList();
for (var i = 0; i < topicFilters.Count; i++)
{
result.Add(new MqttSubscribeResult(topicFilters[i], response.SubscribeReturnCodes[i]));
}
return result;
} }
public async Task Unsubscribe(params string[] topicFilters) public Task Unsubscribe(params string[] topicFilters)
{ {
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
await Unsubscribe(topicFilters.ToList()); return Unsubscribe(topicFilters.ToList());
} }
public async Task Unsubscribe(IList<string> topicFilters) public async Task Unsubscribe(IList<string> topicFilters)
@@ -280,14 +275,14 @@ namespace MQTTnet.Core.Client
FireApplicationMessageReceivedEvent(originalPublishPacket); FireApplicationMessageReceivedEvent(originalPublishPacket);
} }
private async Task SendAsync(MqttBasePacket packet) private Task SendAsync(MqttBasePacket packet)
{ {
await _adapter.SendPacketAsync(packet, _options.DefaultCommunicationTimeout); return _adapter.SendPacketAsync(packet, _options.DefaultCommunicationTimeout);
} }
private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket) where TResponsePacket : MqttBasePacket private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket) where TResponsePacket : MqttBasePacket
{ {
Func<MqttBasePacket, bool> responsePacketSelector = p => bool ResponsePacketSelector(MqttBasePacket p)
{ {
var p1 = p as TResponsePacket; var p1 = p as TResponsePacket;
if (p1 == null) if (p1 == null)
@@ -307,10 +302,10 @@ namespace MQTTnet.Core.Client
} }
return true; return true;
}; }
await _adapter.SendPacketAsync(requestPacket, _options.DefaultCommunicationTimeout); await _adapter.SendPacketAsync(requestPacket, _options.DefaultCommunicationTimeout);
return (TResponsePacket)await _packetDispatcher.WaitForPacketAsync(responsePacketSelector, _options.DefaultCommunicationTimeout); return (TResponsePacket)await _packetDispatcher.WaitForPacketAsync(ResponsePacketSelector, _options.DefaultCommunicationTimeout);
} }
private ushort GetNewPacketIdentifier() private ushort GetNewPacketIdentifier()
@@ -330,8 +325,9 @@ namespace MQTTnet.Core.Client
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket()); await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket());
} }
} }
catch (MqttCommunicationException) catch (MqttCommunicationException exception)
{ {
MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication error while receiving packets.");
} }
catch (Exception exception) catch (Exception exception)
{ {
@@ -357,8 +353,9 @@ namespace MQTTnet.Core.Client
Task.Run(() => ProcessReceivedPacket(mqttPacket), cancellationToken).Forget(); Task.Run(() => ProcessReceivedPacket(mqttPacket), cancellationToken).Forget();
} }
} }
catch (MqttCommunicationException) catch (MqttCommunicationException exception)
{ {
MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication error while receiving packets.");
} }
catch (Exception exception) catch (Exception exception)
{ {
+2
View File
@@ -14,6 +14,8 @@ namespace MQTTnet.Core.Client
public string ClientId { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty); public string ClientId { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty);
public bool CleanSession { get; set; } = true;
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(5); public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(5);
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10); public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
@@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MQTTnet.Core.Internal
{
public class AsyncGate
{
private readonly Queue<TaskCompletionSource<bool>> _waitingTasks = new Queue<TaskCompletionSource<bool>>();
public Task WaitOneAsync()
{
var tcs = new TaskCompletionSource<bool>();
lock (_waitingTasks)
{
_waitingTasks.Enqueue(tcs);
}
return tcs.Task;
}
public void Set()
{
lock (_waitingTasks)
{
if (_waitingTasks.Count > 0)
{
_waitingTasks.Dequeue().SetResult(true);
}
}
}
}
}
+30 -103
View File
@@ -1,107 +1,34 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project ToolsVersion="14.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> <PropertyGroup>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion> <TargetFramework>netstandard1.1</TargetFramework>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.Core</RootNamespace>
<AssemblyName>MQTTnet.Core</AssemblyName> <AssemblyName>MQTTnet.Core</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage> <RootNamespace>MQTTnet.Core</RootNamespace>
<FileAlignment>512</FileAlignment> <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <Description>MQTTnet is a .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).</Description>
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile> <Product>MQTTnet</Product>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <Company>Christian Kratky</Company>
<Authors>Christian Kratky</Authors>
<Version>2.1.2.0</Version>
<PackageId>MQTTnet.Core</PackageId>
<Copyright>Copyright © Christian Kratky 2016-2017</Copyright>
<PackageProjectUrl>https://github.com/chkr1011/MQTTnet</PackageProjectUrl>
<PackageIconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</PackageIconUrl>
<RepositoryUrl>https://github.com/chkr1011/MQTTnet</RepositoryUrl>
<PackageTags>MQTT MQTTClient MQTTServer MQTTBroker Broker</PackageTags>
<FileVersion>2.1.2.0</FileVersion>
<AssemblyVersion>2.1.2.0</AssemblyVersion>
<PackageLicenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</PackageLicenseUrl>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Any CPU|AnyCPU'" />
<DebugType>full</DebugType>
<Optimize>false</Optimize> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Any CPU|x64'" />
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" />
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Any CPU|x86'" />
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Adapter\IMqttCommunicationAdapter.cs" />
<Compile Include="Adapter\IMqttServerAdapter.cs" />
<Compile Include="Adapter\MqttClientConnectedEventArgs.cs" />
<Compile Include="Adapter\MqttConnectingFailedException.cs" />
<Compile Include="Adapter\MqttChannelCommunicationAdapter.cs" />
<Compile Include="Channel\IMqttCommunicationChannel.cs" />
<Compile Include="Client\MqttPacketDispatcher.cs" />
<Compile Include="Client\MqttSubscribeResult.cs" />
<Compile Include="Client\MqttPacketAwaiter.cs" />
<Compile Include="Diagnostics\MqttTrace.cs" />
<Compile Include="Diagnostics\MqttTraceLevel.cs" />
<Compile Include="Diagnostics\MqttTraceMessagePublishedEventArgs.cs" />
<Compile Include="Exceptions\MqttCommunicationException.cs" />
<Compile Include="Exceptions\MqttCommunicationTimedOutException.cs" />
<Compile Include="Exceptions\MqttProtocolViolationException.cs" />
<Compile Include="Internal\MqttApplicationMessageExtensions.cs" />
<Compile Include="MqttApplicationMessageReceivedEventArgs.cs" />
<Compile Include="Packets\IPacketWithPacketIdentifier.cs" />
<Compile Include="Packets\MqttConnAckPacket.cs" />
<Compile Include="Packets\MqttBasePacket.cs" />
<Compile Include="Packets\MqttConnectPacket.cs" />
<Compile Include="Packets\MqttDisconnectPacket.cs" />
<Compile Include="MqttApplicationMessage.cs" />
<Compile Include="Client\MqttClient.cs" />
<Compile Include="Client\MqttClientOptions.cs" />
<Compile Include="Packets\MqttPingReqPacket.cs" />
<Compile Include="Packets\MqttPubCompPacket.cs" />
<Compile Include="Packets\MqttBasePublishPacket.cs" />
<Compile Include="Packets\MqttUnsubAckPacket.cs" />
<Compile Include="Packets\MqttSubAckPacket.cs" />
<Compile Include="Packets\MqttPubRelPacket.cs" />
<Compile Include="Packets\MqttPingRespPacket.cs" />
<Compile Include="Packets\MqttPubAckPacket.cs" />
<Compile Include="Packets\MqttPublishPacket.cs" />
<Compile Include="Packets\MqttPubRecPacket.cs" />
<Compile Include="Packets\MqttUnsubscribe.cs" />
<Compile Include="Packets\MqttSubscribePacket.cs" />
<Compile Include="Packets\TopicFilter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Protocol\MqttConnectReturnCode.cs" />
<Compile Include="Protocol\MqttControlPacketType.cs" />
<Compile Include="Protocol\MqttQualityOfServiceLevel.cs" />
<Compile Include="Protocol\MqttSubscribeReturnCode.cs" />
<Compile Include="Serializer\ByteReader.cs" />
<Compile Include="Serializer\ByteWriter.cs" />
<Compile Include="Serializer\DefaultMqttV311PacketSerializer.cs" />
<Compile Include="Serializer\IMqttPacketSerializer.cs" />
<Compile Include="Serializer\MqttPacketReader.cs" />
<Compile Include="Serializer\MqttPacketWriter.cs" />
<Compile Include="Server\MqttClientSession.cs" />
<Compile Include="Server\MqttClientSessionManager.cs" />
<Compile Include="Server\MqttOutgoingPublicationsManager.cs" />
<Compile Include="Server\MqttServer.cs" />
<Compile Include="Server\MqttServerOptions.cs" />
<Compile Include="Server\MqttClientPublishPacketContext.cs" />
<Compile Include="Server\MqttTopicFilterComparer.cs" />
<Compile Include="Server\MqttClientSubscriptionsManager.cs" />
<Compile Include="Internal\TaskExtensions.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> </Project>
-15
View File
@@ -1,15 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("MQTTnet")]
[assembly: AssemblyDescription("The core library of MQTTnet")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Christian Kratky")]
[assembly: AssemblyProduct("MQTTnet")]
[assembly: AssemblyCopyright("Copyright © Christian Kratky 2016-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("0e10d0ea-8e4b-4903-ab9e-93a187d07922")]
[assembly: AssemblyVersion("2.1.0.4")]
[assembly: AssemblyFileVersion("2.1.0.4")]
+13 -7
View File
@@ -4,36 +4,42 @@ namespace MQTTnet.Core.Serializer
{ {
public class ByteReader public class ByteReader
{ {
private readonly int _source;
private int _index; private int _index;
private readonly int _byte;
public ByteReader(byte @byte) public ByteReader(int source)
{ {
_byte = @byte; _source = source;
} }
public bool Read() public bool Read()
{ {
if (_index >= 8) if (_index >= 8)
{ {
throw new InvalidOperationException("End of the byte reached."); throw new InvalidOperationException("End of byte reached.");
} }
var result = ((1 << _index) & _byte) > 0; var result = ((1 << _index) & _source) > 0;
_index++; _index++;
return result; return result;
} }
public byte Read(int count) public byte Read(int count)
{ {
if (_index + count > 8)
{
throw new InvalidOperationException("End of byte will be reached.");
}
var result = 0; var result = 0;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
if (Read()) if (((1 << _index) & _source) > 0)
{ {
result |= 1 << i; result |= 1 << i;
} }
_index++;
} }
return (byte)result; return (byte)result;
+1 -1
View File
@@ -9,7 +9,7 @@ namespace MQTTnet.Core.Serializer
public byte Value => (byte)_byte; public byte Value => (byte)_byte;
public void Write(byte @byte, int count) public void Write(int @byte, int count)
{ {
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
@@ -1,6 +1,5 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -13,7 +12,7 @@ namespace MQTTnet.Core.Serializer
{ {
public class DefaultMqttV311PacketSerializer : IMqttPacketSerializer public class DefaultMqttV311PacketSerializer : IMqttPacketSerializer
{ {
public async Task SerializeAsync(MqttBasePacket packet, IMqttCommunicationChannel destination) public Task SerializeAsync(MqttBasePacket packet, IMqttCommunicationChannel destination)
{ {
if (packet == null) throw new ArgumentNullException(nameof(packet)); if (packet == null) throw new ArgumentNullException(nameof(packet));
if (destination == null) throw new ArgumentNullException(nameof(destination)); if (destination == null) throw new ArgumentNullException(nameof(destination));
@@ -21,99 +20,85 @@ namespace MQTTnet.Core.Serializer
var connectPacket = packet as MqttConnectPacket; var connectPacket = packet as MqttConnectPacket;
if (connectPacket != null) if (connectPacket != null)
{ {
await SerializeAsync(connectPacket, destination); return SerializeAsync(connectPacket, destination);
return;
} }
var connAckPacket = packet as MqttConnAckPacket; var connAckPacket = packet as MqttConnAckPacket;
if (connAckPacket != null) if (connAckPacket != null)
{ {
await SerializeAsync(connAckPacket, destination); return SerializeAsync(connAckPacket, destination);
return;
} }
var disconnectPacket = packet as MqttDisconnectPacket; var disconnectPacket = packet as MqttDisconnectPacket;
if (disconnectPacket != null) if (disconnectPacket != null)
{ {
await SerializeAsync(disconnectPacket, destination); return SerializeAsync(disconnectPacket, destination);
return;
} }
var pingReqPacket = packet as MqttPingReqPacket; var pingReqPacket = packet as MqttPingReqPacket;
if (pingReqPacket != null) if (pingReqPacket != null)
{ {
await SerializeAsync(pingReqPacket, destination); return SerializeAsync(pingReqPacket, destination);
return;
} }
var pingRespPacket = packet as MqttPingRespPacket; var pingRespPacket = packet as MqttPingRespPacket;
if (pingRespPacket != null) if (pingRespPacket != null)
{ {
await SerializeAsync(pingRespPacket, destination); return SerializeAsync(pingRespPacket, destination);
return;
} }
var publishPacket = packet as MqttPublishPacket; var publishPacket = packet as MqttPublishPacket;
if (publishPacket != null) if (publishPacket != null)
{ {
await SerializeAsync(publishPacket, destination); return SerializeAsync(publishPacket, destination);
return;
} }
var pubAckPacket = packet as MqttPubAckPacket; var pubAckPacket = packet as MqttPubAckPacket;
if (pubAckPacket != null) if (pubAckPacket != null)
{ {
await SerializeAsync(pubAckPacket, destination); return SerializeAsync(pubAckPacket, destination);
return;
} }
var pubRecPacket = packet as MqttPubRecPacket; var pubRecPacket = packet as MqttPubRecPacket;
if (pubRecPacket != null) if (pubRecPacket != null)
{ {
await SerializeAsync(pubRecPacket, destination); return SerializeAsync(pubRecPacket, destination);
return;
} }
var pubRelPacket = packet as MqttPubRelPacket; var pubRelPacket = packet as MqttPubRelPacket;
if (pubRelPacket != null) if (pubRelPacket != null)
{ {
await SerializeAsync(pubRelPacket, destination); return SerializeAsync(pubRelPacket, destination);
return;
} }
var pubCompPacket = packet as MqttPubCompPacket; var pubCompPacket = packet as MqttPubCompPacket;
if (pubCompPacket != null) if (pubCompPacket != null)
{ {
await SerializeAsync(pubCompPacket, destination); return SerializeAsync(pubCompPacket, destination);
return;
} }
var subscribePacket = packet as MqttSubscribePacket; var subscribePacket = packet as MqttSubscribePacket;
if (subscribePacket != null) if (subscribePacket != null)
{ {
await SerializeAsync(subscribePacket, destination); return SerializeAsync(subscribePacket, destination);
return;
} }
var subAckPacket = packet as MqttSubAckPacket; var subAckPacket = packet as MqttSubAckPacket;
if (subAckPacket != null) if (subAckPacket != null)
{ {
await SerializeAsync(subAckPacket, destination); return SerializeAsync(subAckPacket, destination);
return;
} }
var unsubscribePacket = packet as MqttUnsubscribePacket; var unsubscribePacket = packet as MqttUnsubscribePacket;
if (unsubscribePacket != null) if (unsubscribePacket != null)
{ {
await SerializeAsync(unsubscribePacket, destination); return SerializeAsync(unsubscribePacket, destination);
return;
} }
var unsubAckPacket = packet as MqttUnsubAckPacket; var unsubAckPacket = packet as MqttUnsubAckPacket;
if (unsubAckPacket != null) if (unsubAckPacket != null)
{ {
await SerializeAsync(unsubAckPacket, destination); return SerializeAsync(unsubAckPacket, destination);
return;
} }
throw new MqttProtocolViolationException("Packet type invalid."); throw new MqttProtocolViolationException("Packet type invalid.");
@@ -216,7 +201,7 @@ namespace MQTTnet.Core.Serializer
default: default:
{ {
throw new ProtocolViolationException(); throw new MqttProtocolViolationException("Packet type not supported.");
} }
} }
} }
@@ -288,11 +273,12 @@ namespace MQTTnet.Core.Serializer
await reader.ReadRemainingDataByteAsync(); await reader.ReadRemainingDataByteAsync();
await reader.ReadRemainingDataByteAsync(); await reader.ReadRemainingDataByteAsync();
var protocolName = await reader.ReadRemainingDataAsync(4); var protocolName = await reader.ReadRemainingDataAsync(4);
if (Encoding.UTF8.GetString(protocolName, 0, protocolName.Length) != "MQTT") if (Encoding.UTF8.GetString(protocolName, 0, protocolName.Length) != "MQTT")
{ {
throw new ProtocolViolationException("Protocol name is not 'MQTT'."); throw new MqttProtocolViolationException("Protocol name is not 'MQTT'.");
} }
var protocolLevel = await reader.ReadRemainingDataByteAsync(); var protocolLevel = await reader.ReadRemainingDataByteAsync();
@@ -366,12 +352,7 @@ namespace MQTTnet.Core.Serializer
{ {
if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession) if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
{ {
throw new ProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7]."); throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
}
if (!string.IsNullOrEmpty(packet.ClientId) && !Regex.IsMatch(packet.ClientId, "^[a-zA-Z0-9]*$"))
{
throw new ProtocolViolationException("ClientId contains invalid characters [MQTT-3.1.3-5].");
} }
} }
@@ -379,23 +360,21 @@ namespace MQTTnet.Core.Serializer
{ {
if (packet.QualityOfServiceLevel == 0 && packet.Dup) if (packet.QualityOfServiceLevel == 0 && packet.Dup)
{ {
throw new ProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2]."); throw new MqttProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
} }
} }
private async Task SerializeAsync(MqttConnectPacket packet, IMqttCommunicationChannel destination) private static readonly byte[] MqttPrefix = Encoding.UTF8.GetBytes("MQTT");
private Task SerializeAsync(MqttConnectPacket packet, IMqttCommunicationChannel destination)
{ {
ValidateConnectPacket(packet); ValidateConnectPacket(packet);
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
// Write variable header // Write variable header
output.Write(0x00); // 3.1.2.1 Protocol Name output.Write(0x00, 0x04); // 3.1.2.1 Protocol Name
output.Write(0x04); // "" output.Write(MqttPrefix);
output.Write('M');
output.Write('Q');
output.Write('T');
output.Write('T');
output.Write(0x04); // 3.1.2.2 Protocol Level output.Write(0x04); // 3.1.2.2 Protocol Level
var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags
@@ -405,7 +384,7 @@ namespace MQTTnet.Core.Serializer
if (packet.WillMessage != null) if (packet.WillMessage != null)
{ {
connectFlags.Write((byte)packet.WillMessage.QualityOfServiceLevel, 2); connectFlags.Write((int)packet.WillMessage.QualityOfServiceLevel, 2);
connectFlags.Write(packet.WillMessage.Retain); connectFlags.Write(packet.WillMessage.Retain);
} }
else else
@@ -413,7 +392,7 @@ namespace MQTTnet.Core.Serializer
connectFlags.Write(0, 2); connectFlags.Write(0, 2);
connectFlags.Write(false); connectFlags.Write(false);
} }
connectFlags.Write(packet.Password != null); connectFlags.Write(packet.Password != null);
connectFlags.Write(packet.Username != null); connectFlags.Write(packet.Username != null);
@@ -438,11 +417,11 @@ namespace MQTTnet.Core.Serializer
} }
output.InjectFixedHeader(MqttControlPacketType.Connect); output.InjectFixedHeader(MqttControlPacketType.Connect);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttConnAckPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttConnAckPacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
@@ -453,26 +432,26 @@ namespace MQTTnet.Core.Serializer
output.Write((byte)packet.ConnectReturnCode); output.Write((byte)packet.ConnectReturnCode);
output.InjectFixedHeader(MqttControlPacketType.ConnAck); output.InjectFixedHeader(MqttControlPacketType.ConnAck);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttDisconnectPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttDisconnectPacket packet, IMqttCommunicationChannel destination)
{ {
await SerializeEmptyPacketAsync(MqttControlPacketType.Disconnect, destination); return SerializeEmptyPacketAsync(MqttControlPacketType.Disconnect, destination);
} }
private async Task SerializeAsync(MqttPingReqPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttPingReqPacket packet, IMqttCommunicationChannel destination)
{ {
await SerializeEmptyPacketAsync(MqttControlPacketType.PingReq, destination); return SerializeEmptyPacketAsync(MqttControlPacketType.PingReq, destination);
} }
private async Task SerializeAsync(MqttPingRespPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttPingRespPacket packet, IMqttCommunicationChannel destination)
{ {
await SerializeEmptyPacketAsync(MqttControlPacketType.PingResp, destination); return SerializeEmptyPacketAsync(MqttControlPacketType.PingResp, destination);
} }
private async Task SerializeAsync(MqttPublishPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttPublishPacket packet, IMqttCommunicationChannel destination)
{ {
ValidatePublishPacket(packet); ValidatePublishPacket(packet);
@@ -503,29 +482,29 @@ namespace MQTTnet.Core.Serializer
fixedHeader.Write(packet.Dup); fixedHeader.Write(packet.Dup);
output.InjectFixedHeader(MqttControlPacketType.Publish, fixedHeader.Value); output.InjectFixedHeader(MqttControlPacketType.Publish, fixedHeader.Value);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttPubAckPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttPubAckPacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
output.Write(packet.PacketIdentifier); output.Write(packet.PacketIdentifier);
output.InjectFixedHeader(MqttControlPacketType.PubAck); output.InjectFixedHeader(MqttControlPacketType.PubAck);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttPubRecPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttPubRecPacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
output.Write(packet.PacketIdentifier); output.Write(packet.PacketIdentifier);
output.InjectFixedHeader(MqttControlPacketType.PubRec); output.InjectFixedHeader(MqttControlPacketType.PubRec);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
@@ -540,24 +519,24 @@ namespace MQTTnet.Core.Serializer
} }
} }
private async Task SerializeAsync(MqttPubCompPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttPubCompPacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
output.Write(packet.PacketIdentifier); output.Write(packet.PacketIdentifier);
output.InjectFixedHeader(MqttControlPacketType.PubComp); output.InjectFixedHeader(MqttControlPacketType.PubComp);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttSubscribePacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttSubscribePacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
output.Write(packet.PacketIdentifier); output.Write(packet.PacketIdentifier);
if (packet.TopicFilters?.Any() == true) if (packet.TopicFilters?.Count > 0)
{ {
foreach (var topicFilter in packet.TopicFilters) foreach (var topicFilter in packet.TopicFilters)
{ {
@@ -567,11 +546,11 @@ namespace MQTTnet.Core.Serializer
} }
output.InjectFixedHeader(MqttControlPacketType.Subscribe, 0x02); output.InjectFixedHeader(MqttControlPacketType.Subscribe, 0x02);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttSubAckPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttSubAckPacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
@@ -586,11 +565,11 @@ namespace MQTTnet.Core.Serializer
} }
output.InjectFixedHeader(MqttControlPacketType.SubAck); output.InjectFixedHeader(MqttControlPacketType.SubAck);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttUnsubscribePacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttUnsubscribePacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
@@ -605,27 +584,27 @@ namespace MQTTnet.Core.Serializer
} }
output.InjectFixedHeader(MqttControlPacketType.Unsubscibe, 0x02); output.InjectFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeAsync(MqttUnsubAckPacket packet, IMqttCommunicationChannel destination) private Task SerializeAsync(MqttUnsubAckPacket packet, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
output.Write(packet.PacketIdentifier); output.Write(packet.PacketIdentifier);
output.InjectFixedHeader(MqttControlPacketType.UnsubAck); output.InjectFixedHeader(MqttControlPacketType.UnsubAck);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
private async Task SerializeEmptyPacketAsync(MqttControlPacketType type, IMqttCommunicationChannel destination) private Task SerializeEmptyPacketAsync(MqttControlPacketType type, IMqttCommunicationChannel destination)
{ {
using (var output = new MqttPacketWriter()) using (var output = new MqttPacketWriter())
{ {
output.InjectFixedHeader(type); output.InjectFixedHeader(type);
await output.WriteToAsync(destination); return output.WriteToAsync(destination);
} }
} }
} }
+3 -2
View File
@@ -107,15 +107,16 @@ namespace MQTTnet.Core.Serializer
return await ReadRemainingDataAsync(length); return await ReadRemainingDataAsync(length);
} }
public async Task<byte[]> ReadRemainingDataAsync() public Task<byte[]> ReadRemainingDataAsync()
{ {
return await ReadRemainingDataAsync(RemainingLength - (int)_remainingData.Position); return ReadRemainingDataAsync(RemainingLength - (int)_remainingData.Position);
} }
public async Task<byte[]> ReadRemainingDataAsync(int length) public async Task<byte[]> ReadRemainingDataAsync(int length)
{ {
var buffer = new byte[length]; var buffer = new byte[length];
await _remainingData.ReadAsync(buffer, 0, buffer.Length); await _remainingData.ReadAsync(buffer, 0, buffer.Length);
return buffer; return buffer;
} }
+30 -32
View File
@@ -9,7 +9,7 @@ namespace MQTTnet.Core.Serializer
{ {
public sealed class MqttPacketWriter : IDisposable public sealed class MqttPacketWriter : IDisposable
{ {
private readonly MemoryStream _buffer = new MemoryStream(); private readonly MemoryStream _buffer = new MemoryStream(512);
public void InjectFixedHeader(byte fixedHeader) public void InjectFixedHeader(byte fixedHeader)
{ {
@@ -20,31 +20,28 @@ namespace MQTTnet.Core.Serializer
return; return;
} }
var backupBuffer = _buffer.ToArray();
var remainingLength = (int)_buffer.Length; var remainingLength = (int)_buffer.Length;
using (var buffer = new MemoryStream())
_buffer.SetLength(0);
_buffer.WriteByte(fixedHeader);
// Alorithm taken from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html.
var x = remainingLength;
do
{ {
_buffer.WriteTo(buffer); var encodedByte = x % 128;
_buffer.SetLength(0); x = x / 128;
if (x > 0)
_buffer.WriteByte(fixedHeader);
// Alorithm taken from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html.
var x = remainingLength;
do
{ {
var encodedByte = (byte)(x % 128); encodedByte = encodedByte | 128;
x = x / 128; }
if (x > 0)
{
encodedByte = (byte)(encodedByte | 128);
}
_buffer.WriteByte(encodedByte); _buffer.WriteByte((byte)encodedByte);
} while (x > 0); } while (x > 0);
buffer.Position = 0; _buffer.Write(backupBuffer, 0, backupBuffer.Length);
buffer.WriteTo(_buffer);
}
} }
public void InjectFixedHeader(MqttControlPacketType packetType, byte flags = 0) public void InjectFixedHeader(MqttControlPacketType packetType, byte flags = 0)
@@ -59,11 +56,6 @@ namespace MQTTnet.Core.Serializer
_buffer.WriteByte(value); _buffer.WriteByte(value);
} }
public void Write(char value)
{
_buffer.WriteByte((byte)value);
}
public void Write(ushort value) public void Write(ushort value)
{ {
var buffer = BitConverter.GetBytes(value); var buffer = BitConverter.GetBytes(value);
@@ -73,11 +65,15 @@ namespace MQTTnet.Core.Serializer
public void Write(ByteWriter value) public void Write(ByteWriter value)
{ {
if (value == null) throw new ArgumentNullException(nameof(value));
_buffer.WriteByte(value.Value); _buffer.WriteByte(value.Value);
} }
public void Write(byte[] value) public void Write(params byte[] value)
{ {
if (value == null) throw new ArgumentNullException(nameof(value));
_buffer.Write(value, 0, value.Length); _buffer.Write(value, 0, value.Length);
} }
@@ -94,14 +90,16 @@ namespace MQTTnet.Core.Serializer
Write(value); Write(value);
} }
public Task WriteToAsync(IMqttCommunicationChannel destination)
{
if (destination == null) throw new ArgumentNullException(nameof(destination));
return destination.WriteAsync(_buffer.ToArray());
}
public void Dispose() public void Dispose()
{ {
_buffer?.Dispose(); _buffer?.Dispose();
} }
public async Task WriteToAsync(IMqttCommunicationChannel destination)
{
await destination.WriteAsync(_buffer.ToArray());
}
} }
} }
@@ -0,0 +1,9 @@
namespace MQTTnet.Core.Server
{
public class GetOrCreateClientSessionResult
{
public bool IsExistingSession { get; set; }
public MqttClientSession Session { get; set; }
}
}
@@ -11,16 +11,16 @@ using MQTTnet.Core.Packets;
namespace MQTTnet.Core.Server namespace MQTTnet.Core.Server
{ {
public class MqttOutgoingPublicationsManager public class MqttClientMessageQueue
{ {
private readonly AutoResetEvent _resetEvent = new AutoResetEvent(false);
private readonly List<MqttClientPublishPacketContext> _pendingPublishPackets = new List<MqttClientPublishPacketContext>(); private readonly List<MqttClientPublishPacketContext> _pendingPublishPackets = new List<MqttClientPublishPacketContext>();
private readonly AsyncGate _gate = new AsyncGate();
private readonly MqttServerOptions _options; private readonly MqttServerOptions _options;
private CancellationTokenSource _cancellationTokenSource; private CancellationTokenSource _cancellationTokenSource;
private IMqttCommunicationAdapter _adapter; private IMqttCommunicationAdapter _adapter;
public MqttOutgoingPublicationsManager(MqttServerOptions options) public MqttClientMessageQueue(MqttServerOptions options)
{ {
_options = options ?? throw new ArgumentNullException(nameof(options)); _options = options ?? throw new ArgumentNullException(nameof(options));
} }
@@ -29,17 +29,18 @@ namespace MQTTnet.Core.Server
{ {
if (_cancellationTokenSource != null) if (_cancellationTokenSource != null)
{ {
throw new InvalidOperationException($"{nameof(MqttOutgoingPublicationsManager)} already started."); throw new InvalidOperationException($"{nameof(MqttClientMessageQueue)} already started.");
} }
_adapter = adapter ?? throw new ArgumentNullException(nameof(adapter)); _adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));
_cancellationTokenSource = new CancellationTokenSource(); _cancellationTokenSource = new CancellationTokenSource();
Task.Run(async () => await SendPendingPublishPacketsAsync(_cancellationTokenSource.Token)).Forget(); Task.Run(() => SendPendingPublishPacketsAsync(_cancellationTokenSource.Token));
} }
public void Stop() public void Stop()
{ {
_adapter = null;
_cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Cancel();
_cancellationTokenSource = null; _cancellationTokenSource = null;
} }
@@ -52,7 +53,7 @@ namespace MQTTnet.Core.Server
lock (_pendingPublishPackets) lock (_pendingPublishPackets)
{ {
_pendingPublishPackets.Add(new MqttClientPublishPacketContext(senderClientSession, publishPacket)); _pendingPublishPackets.Add(new MqttClientPublishPacketContext(senderClientSession, publishPacket));
_resetEvent.Set(); _gate.Set();
} }
} }
@@ -62,12 +63,17 @@ namespace MQTTnet.Core.Server
{ {
try try
{ {
_resetEvent.WaitOne(); await _gate.WaitOneAsync();
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
return; return;
} }
if (_adapter == null)
{
continue;
}
List<MqttClientPublishPacketContext> pendingPublishPackets; List<MqttClientPublishPacketContext> pendingPublishPackets;
lock (_pendingPublishPackets) lock (_pendingPublishPackets)
{ {
@@ -81,7 +87,7 @@ namespace MQTTnet.Core.Server
} }
catch (Exception e) catch (Exception e)
{ {
MqttTrace.Error(nameof(MqttOutgoingPublicationsManager), e, "Error while sending pending publish packets."); MqttTrace.Error(nameof(MqttClientMessageQueue), e, "Error while sending pending publish packets.");
} }
finally finally
{ {
@@ -106,11 +112,11 @@ namespace MQTTnet.Core.Server
} }
catch (MqttCommunicationException exception) catch (MqttCommunicationException exception)
{ {
MqttTrace.Warning(nameof(MqttOutgoingPublicationsManager), exception, "Sending publish packet failed."); MqttTrace.Warning(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
} }
catch (Exception exception) catch (Exception exception)
{ {
MqttTrace.Error(nameof(MqttOutgoingPublicationsManager), exception, "Sending publish packet failed."); MqttTrace.Error(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
} }
finally finally
{ {
+29 -25
View File
@@ -11,12 +11,12 @@ using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server namespace MQTTnet.Core.Server
{ {
public class MqttClientSession public sealed class MqttClientSession : IDisposable
{ {
private readonly ConcurrentDictionary<ushort, MqttPublishPacket> _pendingIncomingPublications = new ConcurrentDictionary<ushort, MqttPublishPacket>(); private readonly ConcurrentDictionary<ushort, MqttPublishPacket> _pendingIncomingPublications = new ConcurrentDictionary<ushort, MqttPublishPacket>();
private readonly MqttClientSubscriptionsManager _subscriptionsManager = new MqttClientSubscriptionsManager(); private readonly MqttClientSubscriptionsManager _subscriptionsManager = new MqttClientSubscriptionsManager();
private readonly MqttOutgoingPublicationsManager _outgoingPublicationsManager; private readonly MqttClientMessageQueue _messageQueue;
private readonly Action<MqttClientSession, MqttPublishPacket> _publishPacketReceivedCallback; private readonly Action<MqttClientSession, MqttPublishPacket> _publishPacketReceivedCallback;
private readonly MqttServerOptions _options; private readonly MqttServerOptions _options;
@@ -24,15 +24,17 @@ namespace MQTTnet.Core.Server
private IMqttCommunicationAdapter _adapter; private IMqttCommunicationAdapter _adapter;
private string _identifier; private string _identifier;
private MqttApplicationMessage _willApplicationMessage; private MqttApplicationMessage _willApplicationMessage;
public MqttClientSession(MqttServerOptions options, Action<MqttClientSession, MqttPublishPacket> publishPacketReceivedCallback) public MqttClientSession(MqttServerOptions options, Action<MqttClientSession, MqttPublishPacket> publishPacketReceivedCallback)
{ {
_options = options ?? throw new ArgumentNullException(nameof(options)); _options = options ?? throw new ArgumentNullException(nameof(options));
_publishPacketReceivedCallback = publishPacketReceivedCallback ?? throw new ArgumentNullException(nameof(publishPacketReceivedCallback)); _publishPacketReceivedCallback = publishPacketReceivedCallback ?? throw new ArgumentNullException(nameof(publishPacketReceivedCallback));
_outgoingPublicationsManager = new MqttOutgoingPublicationsManager(options); _messageQueue = new MqttClientMessageQueue(options);
} }
public bool IsConnected => _adapter != null;
public async Task RunAsync(string identifier, MqttApplicationMessage willApplicationMessage, IMqttCommunicationAdapter adapter) public async Task RunAsync(string identifier, MqttApplicationMessage willApplicationMessage, IMqttCommunicationAdapter adapter)
{ {
if (adapter == null) throw new ArgumentNullException(nameof(adapter)); if (adapter == null) throw new ArgumentNullException(nameof(adapter));
@@ -45,7 +47,7 @@ namespace MQTTnet.Core.Server
_adapter = adapter; _adapter = adapter;
_cancellationTokenSource = new CancellationTokenSource(); _cancellationTokenSource = new CancellationTokenSource();
_outgoingPublicationsManager.Start(adapter); _messageQueue.Start(adapter);
while (!_cancellationTokenSource.IsCancellationRequested) while (!_cancellationTokenSource.IsCancellationRequested)
{ {
var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero); var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero);
@@ -65,8 +67,8 @@ namespace MQTTnet.Core.Server
{ {
_publishPacketReceivedCallback(this, _willApplicationMessage.ToPublishPacket()); _publishPacketReceivedCallback(this, _willApplicationMessage.ToPublishPacket());
} }
_outgoingPublicationsManager.Stop(); _messageQueue.Stop();
_cancellationTokenSource.Cancel(); _cancellationTokenSource.Cancel();
_adapter = null; _adapter = null;
@@ -74,7 +76,7 @@ namespace MQTTnet.Core.Server
} }
} }
public void DispatchPublishPacket(MqttClientSession senderClientSession, MqttPublishPacket publishPacket) public void EnqueuePublishPacket(MqttClientSession senderClientSession, MqttPublishPacket publishPacket)
{ {
if (senderClientSession == null) throw new ArgumentNullException(nameof(senderClientSession)); if (senderClientSession == null) throw new ArgumentNullException(nameof(senderClientSession));
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
@@ -84,66 +86,68 @@ namespace MQTTnet.Core.Server
return; return;
} }
_outgoingPublicationsManager.Enqueue(senderClientSession, publishPacket); _messageQueue.Enqueue(senderClientSession, publishPacket);
MqttTrace.Verbose(nameof(MqttClientSession), $"Client '{_identifier}: Enqueued pending publish packet."); MqttTrace.Verbose(nameof(MqttClientSession), $"Client '{_identifier}: Enqueued pending publish packet.");
} }
private async Task HandleIncomingPacketAsync(MqttBasePacket packet) public void Dispose()
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
}
private Task HandleIncomingPacketAsync(MqttBasePacket packet)
{ {
var subscribePacket = packet as MqttSubscribePacket; var subscribePacket = packet as MqttSubscribePacket;
if (subscribePacket != null) if (subscribePacket != null)
{ {
await _adapter.SendPacketAsync(_subscriptionsManager.Subscribe(subscribePacket), _options.DefaultCommunicationTimeout); return _adapter.SendPacketAsync(_subscriptionsManager.Subscribe(subscribePacket), _options.DefaultCommunicationTimeout);
return;
} }
var unsubscribePacket = packet as MqttUnsubscribePacket; var unsubscribePacket = packet as MqttUnsubscribePacket;
if (unsubscribePacket != null) if (unsubscribePacket != null)
{ {
await _adapter.SendPacketAsync(_subscriptionsManager.Unsubscribe(unsubscribePacket), _options.DefaultCommunicationTimeout); return _adapter.SendPacketAsync(_subscriptionsManager.Unsubscribe(unsubscribePacket), _options.DefaultCommunicationTimeout);
return;
} }
var publishPacket = packet as MqttPublishPacket; var publishPacket = packet as MqttPublishPacket;
if (publishPacket != null) if (publishPacket != null)
{ {
await HandleIncomingPublishPacketAsync(publishPacket); return HandleIncomingPublishPacketAsync(publishPacket);
return;
} }
var pubRelPacket = packet as MqttPubRelPacket; var pubRelPacket = packet as MqttPubRelPacket;
if (pubRelPacket != null) if (pubRelPacket != null)
{ {
await HandleIncomingPubRelPacketAsync(pubRelPacket); return HandleIncomingPubRelPacketAsync(pubRelPacket);
return;
} }
var pubAckPacket = packet as MqttPubAckPacket; var pubAckPacket = packet as MqttPubAckPacket;
if (pubAckPacket != null) if (pubAckPacket != null)
{ {
await HandleIncomingPubAckPacketAsync(pubAckPacket); return HandleIncomingPubAckPacketAsync(pubAckPacket);
return;
} }
if (packet is MqttPingReqPacket) if (packet is MqttPingReqPacket)
{ {
await _adapter.SendPacketAsync(new MqttPingRespPacket(), _options.DefaultCommunicationTimeout); return _adapter.SendPacketAsync(new MqttPingRespPacket(), _options.DefaultCommunicationTimeout);
return;
} }
if (packet is MqttDisconnectPacket || packet is MqttConnectPacket) if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
{ {
_cancellationTokenSource.Cancel(); _cancellationTokenSource.Cancel();
return; return Task.FromResult((object)null);
} }
MqttTrace.Warning(nameof(MqttClientSession), $"Client '{_identifier}': Received not supported packet ({packet}). Closing connection."); MqttTrace.Warning(nameof(MqttClientSession), $"Client '{_identifier}': Received not supported packet ({packet}). Closing connection.");
_cancellationTokenSource.Cancel(); _cancellationTokenSource.Cancel();
return Task.FromResult((object)null);
} }
private async Task HandleIncomingPubAckPacketAsync(MqttPubAckPacket pubAckPacket) private async Task HandleIncomingPubAckPacketAsync(MqttPubAckPacket pubAckPacket)
{ {
await Task.FromResult(0); await Task.FromResult((object)null);
} }
private async Task HandleIncomingPublishPacketAsync(MqttPublishPacket publishPacket) private async Task HandleIncomingPublishPacketAsync(MqttPublishPacket publishPacket)
@@ -1,93 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server
{
public class MqttClientSessionManager
{
private readonly ConcurrentDictionary<string, MqttClientSession> _clientSessions = new ConcurrentDictionary<string, MqttClientSession>();
private readonly MqttServerOptions _options;
public MqttClientSessionManager(MqttServerOptions options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public async Task RunClientSessionAsync(MqttClientConnectedEventArgs eventArgs)
{
try
{
var connectPacket = await eventArgs.ClientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout) as MqttConnectPacket;
if (connectPacket == null)
{
throw new MqttProtocolViolationException("The first packet from a client must be a 'Connect' packet [MQTT-3.1.0-1].");
}
var connectReturnCode = MqttConnectReturnCode.ConnectionAccepted;
if (_options.ConnectionValidator != null)
{
connectReturnCode = _options.ConnectionValidator(connectPacket);
}
MqttClientSession clientSession = null;
var isSessionPresent = _clientSessions.ContainsKey(connectPacket.ClientId);
if (isSessionPresent && connectPacket.CleanSession)
{
MqttClientSession _;
_clientSessions.TryRemove(connectPacket.ClientId, out _);
}
else if (!connectPacket.CleanSession)
{
_clientSessions.TryGetValue(connectPacket.ClientId, out clientSession);
}
await eventArgs.ClientAdapter.SendPacketAsync(new MqttConnAckPacket
{
ConnectReturnCode = connectReturnCode,
IsSessionPresent = clientSession != null
}, _options.DefaultCommunicationTimeout);
if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
{
return;
}
if (clientSession == null)
{
clientSession = new MqttClientSession(_options, DispatchPublishPacket);
_clientSessions.TryAdd(connectPacket.ClientId, clientSession);
}
await clientSession.RunAsync(eventArgs.Identifier, connectPacket.WillMessage, eventArgs.ClientAdapter);
}
catch (Exception exception)
{
MqttTrace.Error(nameof(MqttServer), exception, exception.Message);
}
finally
{
await eventArgs.ClientAdapter.DisconnectAsync();
}
}
public void Clear()
{
_clientSessions.Clear();
}
private void DispatchPublishPacket(MqttClientSession senderClientSession, MqttPublishPacket publishPacket)
{
foreach (var clientSession in _clientSessions.Values.ToList())
{
clientSession.DispatchPublishPacket(senderClientSession, publishPacket);
}
}
}
}
@@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server
{
public class MqttClientSessionsManager
{
private readonly object _syncRoot = new object();
private readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>();
private readonly MqttServerOptions _options;
public MqttClientSessionsManager(MqttServerOptions options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public async Task RunClientSessionAsync(MqttClientConnectedEventArgs eventArgs)
{
try
{
var connectPacket = await eventArgs.ClientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout) as MqttConnectPacket;
if (connectPacket == null)
{
throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1].");
}
var connectReturnCode = ValidateConnection(connectPacket);
if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
{
await eventArgs.ClientAdapter.SendPacketAsync(new MqttConnAckPacket
{
ConnectReturnCode = connectReturnCode
}, _options.DefaultCommunicationTimeout);
return;
}
var clientSession = GetOrCreateClientSession(connectPacket);
await eventArgs.ClientAdapter.SendPacketAsync(new MqttConnAckPacket
{
ConnectReturnCode = connectReturnCode,
IsSessionPresent = clientSession.IsExistingSession
}, _options.DefaultCommunicationTimeout);
await clientSession.Session.RunAsync(eventArgs.Identifier, connectPacket.WillMessage, eventArgs.ClientAdapter);
}
catch (Exception exception)
{
MqttTrace.Error(nameof(MqttServer), exception, exception.Message);
}
finally
{
await eventArgs.ClientAdapter.DisconnectAsync();
}
}
public void Clear()
{
lock (_syncRoot)
{
_clientSessions.Clear();
}
}
public IList<string> GetConnectedClients()
{
lock (_syncRoot)
{
return _clientSessions.Where(s => s.Value.IsConnected).Select(s => s.Key).ToList();
}
}
private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
{
if (_options.ConnectionValidator != null)
{
return _options.ConnectionValidator(connectPacket);
}
return MqttConnectReturnCode.ConnectionAccepted;
}
private GetOrCreateClientSessionResult GetOrCreateClientSession(MqttConnectPacket connectPacket)
{
lock (_syncRoot)
{
MqttClientSession clientSession;
var isSessionPresent = _clientSessions.TryGetValue(connectPacket.ClientId, out clientSession);
if (isSessionPresent)
{
if (connectPacket.CleanSession)
{
_clientSessions.Remove(connectPacket.ClientId);
clientSession.Dispose();
clientSession = null;
MqttTrace.Verbose(nameof(MqttClientSessionsManager), $"Disposed existing session of client '{connectPacket.ClientId}'.");
}
else
{
MqttTrace.Verbose(nameof(MqttClientSessionsManager), $"Reusing existing session of client '{connectPacket.ClientId}'.");
}
}
var isExistingSession = true;
if (clientSession == null)
{
isExistingSession = false;
clientSession = new MqttClientSession(_options, DispatchPublishPacket);
_clientSessions[connectPacket.ClientId] = clientSession;
MqttTrace.Verbose(nameof(MqttClientSessionsManager), $"Created a new session for client '{connectPacket.ClientId}'.");
}
return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession };
}
}
private void DispatchPublishPacket(MqttClientSession senderClientSession, MqttPublishPacket publishPacket)
{
foreach (var clientSession in _clientSessions.Values.ToList())
{
clientSession.EnqueuePublishPacket(senderClientSession, publishPacket);
}
}
}
}
+17 -9
View File
@@ -1,15 +1,15 @@
using System; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Core.Adapter; using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Internal;
namespace MQTTnet.Core.Server namespace MQTTnet.Core.Server
{ {
public class MqttServer public class MqttServer
{ {
private readonly MqttClientSessionManager _clientSessionManager; private readonly MqttClientSessionsManager _clientSessionsManager;
private readonly IMqttServerAdapter _adapter; private readonly IMqttServerAdapter _adapter;
private readonly MqttServerOptions _options; private readonly MqttServerOptions _options;
@@ -20,22 +20,28 @@ namespace MQTTnet.Core.Server
_options = options ?? throw new ArgumentNullException(nameof(options)); _options = options ?? throw new ArgumentNullException(nameof(options));
_adapter = adapter ?? throw new ArgumentNullException(nameof(adapter)); _adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));
_clientSessionManager = new MqttClientSessionManager(options); _clientSessionsManager = new MqttClientSessionsManager(options);
} }
public IList<string> GetConnectedClients()
{
return _clientSessionsManager.GetConnectedClients();
}
public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
public void InjectClient(string identifier, IMqttCommunicationAdapter adapter) public void InjectClient(string identifier, IMqttCommunicationAdapter adapter)
{ {
if (adapter == null) throw new ArgumentNullException(nameof(adapter)); if (adapter == null) throw new ArgumentNullException(nameof(adapter));
if (_cancellationTokenSource == null) throw new InvalidOperationException("The MQTT server is not started.");
OnClientConnected(this, new MqttClientConnectedEventArgs(identifier, adapter)); OnClientConnected(this, new MqttClientConnectedEventArgs(identifier, adapter));
} }
public void Start() public void Start()
{ {
if (_cancellationTokenSource != null) if (_cancellationTokenSource != null) throw new InvalidOperationException("The MQTT server is already started.");
{
throw new InvalidOperationException("The server is already started.");
}
_cancellationTokenSource = new CancellationTokenSource(); _cancellationTokenSource = new CancellationTokenSource();
@@ -53,7 +59,7 @@ namespace MQTTnet.Core.Server
_adapter.ClientConnected -= OnClientConnected; _adapter.ClientConnected -= OnClientConnected;
_adapter.Stop(); _adapter.Stop();
_clientSessionManager.Clear(); _clientSessionsManager.Clear();
MqttTrace.Information(nameof(MqttServer), "Stopped."); MqttTrace.Information(nameof(MqttServer), "Stopped.");
} }
@@ -61,7 +67,9 @@ namespace MQTTnet.Core.Server
private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs) private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs)
{ {
MqttTrace.Information(nameof(MqttServer), $"Client '{eventArgs.Identifier}': Connected."); MqttTrace.Information(nameof(MqttServer), $"Client '{eventArgs.Identifier}': Connected.");
Task.Run(async () => await _clientSessionManager.RunClientSessionAsync(eventArgs), _cancellationTokenSource.Token).Forget(); ClientConnected?.Invoke(this, eventArgs);
Task.Run(() => _clientSessionsManager.RunClientSessionAsync(eventArgs), _cancellationTokenSource.Token);
} }
} }
} }
+55
View File
@@ -0,0 +1,55 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>MQTTnet</id>
<version>2.1.2.0</version>
<authors>Christian Kratky</authors>
<owners>Christian Kratky</owners>
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>MQTTnet is a .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).</description>
<releaseNotes>* [Server] Added support for complex client IDs.
* [Server] Fixed an issue with not correctly removed old client sessions.
* [Server] Several minor performance improvements.
* [Server] An existing client session is no longer closed if a new client connection is invalid.
* [Client] Added support for sending "CleanSession" flag.</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2017</copyright>
<tags>MQTT MQTTClient MQTTServer MQTTBroker Broker</tags>
</metadata>
<files>
<!-- Universal Windows -->
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\Release\MQTTnet.Core.dll" target="lib\uap10.0"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\Release\MQTTnet.dll" target="lib\uap10.0"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\Release\MQTTnet.pri" target="lib\uap10.0"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\ARM\Release\MQTTnet.Core.dll" target="lib\uap10.0-arm"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\ARM\Release\MQTTnet.dll" target="lib\uap10.0-arm"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\ARM\Release\MQTTnet.pri" target="lib\uap10.0-arm"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\x64\Release\MQTTnet.Core.dll" target="lib\uap10.0-x64"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\x64\Release\MQTTnet.dll" target="lib\uap10.0-x64"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\x64\Release\MQTTnet.pri" target="lib\uap10.0-x64"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\x86\Release\MQTTnet.Core.dll" target="lib\uap10.0-x86"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\x86\Release\MQTTnet.dll" target="lib\uap10.0-x86"/>
<file src=".\Frameworks\MQTTnet.UniversalWindows\bin\x86\Release\MQTTnet.pri" target="lib\uap10.0-x86"/>
<!-- .NET Framework -->
<file src=".\Frameworks\MQTTnet.NetFramework\bin\Release\MQTTnet.Core.dll" target="lib\net45"/>
<file src=".\Frameworks\MQTTnet.NetFramework\bin\Release\MQTTnet.dll" target="lib\net45"/>
<file src=".\Frameworks\MQTTnet.NetFramework\bin\x86\Release\MQTTnet.Core.dll" target="lib\net45-x86"/>
<file src=".\Frameworks\MQTTnet.NetFramework\bin\x86\Release\MQTTnet.dll" target="lib\net45-x86"/>
<file src=".\Frameworks\MQTTnet.NetFramework\bin\x86\Release\MQTTnet.Core.dll" target="lib\net45-x64"/>
<file src=".\Frameworks\MQTTnet.NetFramework\bin\x86\Release\MQTTnet.dll" target="lib\net45-x64"/>
<!-- .NET Core App -->
<file src=".\Frameworks\MQTTnet.NetCoreApp\bin\Release\netcoreapp1.1\MQTTnet.Core.dll" target="lib\netcoreapp1.1"/>
<file src=".\Frameworks\MQTTnet.NetCoreApp\bin\Release\netcoreapp1.1\MQTTnet.dll" target="lib\netcoreapp1.1"/>
</files>
</package>
+135 -70
View File
@@ -1,10 +1,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26228.4 VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Core", "MQTTnet.Core\MQTTnet.Core.csproj", "{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestMqttClient", "Tests\MQTTnet.TestMqttClient\MQTTnet.TestMqttClient.csproj", "{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestMqttClient", "Tests\MQTTnet.TestMqttClient\MQTTnet.TestMqttClient.csproj", "{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
@@ -15,14 +13,25 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.UniversalWindows",
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.NetCore", "Frameworks\MQTTnet.NetCore\MQTTnet.NetCore.csproj", "{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frameworks", "Frameworks", "{32A630A7-2598-41D7-B625-204CD906F5FB}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frameworks", "Frameworks", "{32A630A7-2598-41D7-B625-204CD906F5FB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestMqttServer", "Tests\MQTTnet.TestMqttServer\MQTTnet.TestMqttServer.csproj", "{6F8C0C0C-59EC-4921-9267-370AE113C34F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestMqttServer", "Tests\MQTTnet.TestMqttServer\MQTTnet.TestMqttServer.csproj", "{6F8C0C0C-59EC-4921-9267-370AE113C34F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Core", "MQTTnet.Core\MQTTnet.Core.csproj", "{2ECB99E4-72D0-4C23-99BA-93D511D3967D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{002203AF-2565-4C0D-95ED-027FDEFE0C35}"
ProjectSection(SolutionItems) = preProject
MQTTnet.nuspec = MQTTnet.nuspec
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.NetCoreApp", "Frameworks\MQTTnet.NetCoreApp\MQTTnet.NetCoreApp.csproj", "{1A1B7F51-5328-4395-9D9C-07D70965825E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Any CPU|Any CPU = Any CPU|Any CPU
Any CPU|ARM = Any CPU|ARM
Any CPU|x64 = Any CPU|x64
Any CPU|x86 = Any CPU|x86
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
@@ -33,70 +42,86 @@ Global
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|ARM.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|ARM.ActiveCfg = Any CPU|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|ARM.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|ARM.Build.0 = Any CPU|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x64.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|x64.ActiveCfg = Any CPU|x64
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x64.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|x64.Build.0 = Any CPU|x64
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x86.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|x86.ActiveCfg = Any CPU|x86
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x86.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Any CPU|x86.Build.0 = Any CPU|x86
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|Any CPU.Build.0 = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|ARM.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|ARM.Build.0 = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x64.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x64.Build.0 = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x86.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x86.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|ARM.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|ARM.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|ARM.Build.0 = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x64.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x64.ActiveCfg = Debug|x64
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x64.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x64.Build.0 = Debug|x64
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x86.ActiveCfg = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x86.ActiveCfg = Debug|x86
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x86.Build.0 = Debug|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x86.Build.0 = Debug|x86
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|Any CPU.Build.0 = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|Any CPU.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|ARM.ActiveCfg = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|ARM.ActiveCfg = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|ARM.Build.0 = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|ARM.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x64.ActiveCfg = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x64.ActiveCfg = Release|x64
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x64.Build.0 = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x64.Build.0 = Release|x64
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x86.ActiveCfg = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x86.ActiveCfg = Release|x86
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x86.Build.0 = Release|Any CPU {7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x86.Build.0 = Release|x86
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|ARM.ActiveCfg = Any CPU|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|ARM.Build.0 = Any CPU|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|x64.ActiveCfg = Any CPU|x64
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|x64.Build.0 = Any CPU|x64
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|x86.ActiveCfg = Any CPU|x86
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Any CPU|x86.Build.0 = Any CPU|x86
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|ARM.ActiveCfg = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|ARM.Build.0 = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|ARM.Build.0 = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x64.ActiveCfg = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x64.ActiveCfg = Debug|x64
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x64.Build.0 = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x64.Build.0 = Debug|x64
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x86.ActiveCfg = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x86.ActiveCfg = Debug|x86
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x86.Build.0 = Debug|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x86.Build.0 = Debug|x86
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|Any CPU.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|Any CPU.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|ARM.ActiveCfg = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|ARM.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|ARM.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|ARM.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.ActiveCfg = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.ActiveCfg = Release|x64
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|x64
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|x86
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|x86
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|ARM.ActiveCfg = Any CPU|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|ARM.Build.0 = Any CPU|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|x64.ActiveCfg = Any CPU|x64
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|x64.Build.0 = Any CPU|x64
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|x86.ActiveCfg = Any CPU|x86
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Any CPU|x86.Build.0 = Any CPU|x86
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|ARM.ActiveCfg = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|ARM.Build.0 = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|ARM.Build.0 = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x64.ActiveCfg = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x64.ActiveCfg = Debug|x64
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x64.Build.0 = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x64.Build.0 = Debug|x64
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x86.ActiveCfg = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x86.ActiveCfg = Debug|x86
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x86.Build.0 = Debug|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x86.Build.0 = Debug|x86
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|Any CPU.Build.0 = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|Any CPU.Build.0 = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|ARM.ActiveCfg = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|ARM.ActiveCfg = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|ARM.Build.0 = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|ARM.Build.0 = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x64.ActiveCfg = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x64.ActiveCfg = Release|x64
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x64.Build.0 = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x64.Build.0 = Release|x64
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x86.ActiveCfg = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x86.ActiveCfg = Release|x86
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x86.Build.0 = Release|Any CPU {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x86.Build.0 = Release|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|ARM.ActiveCfg = Any CPU|ARM
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|ARM.Build.0 = Any CPU|ARM
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|x64.ActiveCfg = Any CPU|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|x64.Build.0 = Any CPU|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|x86.ActiveCfg = Any CPU|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Any CPU|x86.Build.0 = Any CPU|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|Any CPU.Build.0 = Debug|Any CPU {BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|ARM.ActiveCfg = Debug|ARM {BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|ARM.ActiveCfg = Debug|ARM
@@ -113,38 +138,78 @@ Global
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x64.Build.0 = Release|x64 {BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x64.Build.0 = Release|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x86.ActiveCfg = Release|x86 {BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x86.ActiveCfg = Release|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x86.Build.0 = Release|x86 {BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x86.Build.0 = Release|x86
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|ARM.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|ARM.ActiveCfg = Any CPU|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|ARM.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|ARM.Build.0 = Any CPU|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|x64.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|x64.ActiveCfg = Any CPU|x64
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|x64.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|x64.Build.0 = Any CPU|x64
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|x86.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|x86.ActiveCfg = Any CPU|x86
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Debug|x86.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Any CPU|x86.Build.0 = Any CPU|x86
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|Any CPU.Build.0 = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|ARM.ActiveCfg = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|ARM.Build.0 = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|x64.ActiveCfg = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|x64.Build.0 = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|x86.ActiveCfg = Release|Any CPU
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C}.Release|x86.Build.0 = Release|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|ARM.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|ARM.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|ARM.Build.0 = Debug|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x64.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x64.ActiveCfg = Debug|x64
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x64.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x64.Build.0 = Debug|x64
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x86.ActiveCfg = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x86.ActiveCfg = Debug|x86
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x86.Build.0 = Debug|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Debug|x86.Build.0 = Debug|x86
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|Any CPU.ActiveCfg = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|Any CPU.Build.0 = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|Any CPU.Build.0 = Release|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|ARM.ActiveCfg = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|ARM.ActiveCfg = Release|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|ARM.Build.0 = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|ARM.Build.0 = Release|Any CPU
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x64.ActiveCfg = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x64.ActiveCfg = Release|x64
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x64.Build.0 = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x64.Build.0 = Release|x64
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x86.ActiveCfg = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x86.ActiveCfg = Release|x86
{6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x86.Build.0 = Release|Any CPU {6F8C0C0C-59EC-4921-9267-370AE113C34F}.Release|x86.Build.0 = Release|x86
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|ARM.ActiveCfg = Any CPU|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|ARM.Build.0 = Any CPU|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|x64.ActiveCfg = Any CPU|x64
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|x64.Build.0 = Any CPU|x64
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|x86.ActiveCfg = Any CPU|x86
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Any CPU|x86.Build.0 = Any CPU|x86
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|ARM.Build.0 = Debug|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x64.ActiveCfg = Debug|x64
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x64.Build.0 = Debug|x64
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x86.ActiveCfg = Debug|x86
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x86.Build.0 = Debug|x86
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|Any CPU.Build.0 = Release|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|ARM.ActiveCfg = Release|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|ARM.Build.0 = Release|Any CPU
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x64.ActiveCfg = Release|x64
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x64.Build.0 = Release|x64
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x86.ActiveCfg = Release|x86
{2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x86.Build.0 = Release|x86
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|Any CPU.ActiveCfg = Any CPU|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|Any CPU.Build.0 = Any CPU|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|ARM.ActiveCfg = Any CPU|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|ARM.Build.0 = Any CPU|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|x64.ActiveCfg = Any CPU|x64
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|x64.Build.0 = Any CPU|x64
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|x86.ActiveCfg = Any CPU|x86
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Any CPU|x86.Build.0 = Any CPU|x86
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|ARM.Build.0 = Debug|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|x64.ActiveCfg = Debug|x64
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|x64.Build.0 = Debug|x64
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|x86.ActiveCfg = Debug|x86
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Debug|x86.Build.0 = Debug|x86
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|Any CPU.Build.0 = Release|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|ARM.ActiveCfg = Release|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|ARM.Build.0 = Release|Any CPU
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|x64.ActiveCfg = Release|x64
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|x64.Build.0 = Release|x64
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|x86.ActiveCfg = Release|x86
{1A1B7F51-5328-4395-9D9C-07D70965825E}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -154,7 +219,7 @@ Global
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D} = {32A630A7-2598-41D7-B625-204CD906F5FB} {A480EF90-0EAA-4D9A-B271-47A9C47F6F7D} = {32A630A7-2598-41D7-B625-204CD906F5FB}
{BD60C727-D8E8-40C3-B8E3-C95A864AE611} = {32A630A7-2598-41D7-B625-204CD906F5FB} {BD60C727-D8E8-40C3-B8E3-C95A864AE611} = {32A630A7-2598-41D7-B625-204CD906F5FB}
{88BE3FC9-79DC-4440-AC6B-C21BD97C6A3C} = {32A630A7-2598-41D7-B625-204CD906F5FB}
{6F8C0C0C-59EC-4921-9267-370AE113C34F} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {6F8C0C0C-59EC-4921-9267-370AE113C34F} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{1A1B7F51-5328-4395-9D9C-07D70965825E} = {32A630A7-2598-41D7-B625-204CD906F5FB}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
+16 -4
View File
@@ -3,13 +3,25 @@
</p> </p>
# MQTTnet # MQTTnet
MQTTnet is a .NET library for MQTT based communication. It provides a MQTT client and a MQTT server. MQTTnet is a .NET library for MQTT based communication. It provides a MQTT client and a MQTT server. The implementation is based on the documentation from http://mqtt.org/.
## Supported frameworks ## Supported frameworks
* .NET Framework 4.5.2+ * .NET Standard 1.1+
* .NET Core 1.0+ * .NET Core 1.1+
* Universal Windows (UWP) 10.0.10240+ * .NET Core App 1.1+
* .NET Framework 4.5.2+ (x86, x64, AnyCPU)
* Universal Windows (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU)
## Supported MQTT versions
* 3.1.1
## Nuget
This library is available as a nuget package: https://www.nuget.org/packages/MQTTnet/
## Contributions
If you want to contribute to this project just create a pull request.
# MqttClient # MqttClient
## Example ## Example
@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.Core.Tests</RootNamespace> <RootNamespace>MQTTnet.Core.Tests</RootNamespace>
<AssemblyName>MQTTnet.Core.Tests</AssemblyName> <AssemblyName>MQTTnet.Core.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
@@ -30,6 +30,54 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|AnyCPU'">
<OutputPath>bin\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x64'">
<OutputPath>bin\x64\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Any CPU\</OutputPath>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" /> <Reference Include="System" />
@@ -42,6 +90,7 @@
<Compile Include="MqttServerTests.cs" /> <Compile Include="MqttServerTests.cs" />
<Compile Include="MqttSubscriptionsManagerTests.cs" /> <Compile Include="MqttSubscriptionsManagerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestMqttCommunicationAdapter.cs" />
<Compile Include="TestMqttServerAdapter.cs" /> <Compile Include="TestMqttServerAdapter.cs" />
<Compile Include="TopicFilterComparerTests.cs" /> <Compile Include="TopicFilterComparerTests.cs" />
</ItemGroup> </ItemGroup>
@@ -50,7 +99,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj"> <ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project> <Project>{2ecb99e4-72d0-4c23-99ba-93d511d3967d}</Project>
<Name>MQTTnet.Core</Name> <Name>MQTTnet.Core</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
+3 -53
View File
@@ -1,8 +1,5 @@
using System; using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client; using MQTTnet.Core.Client;
using MQTTnet.Core.Packets; using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol; using MQTTnet.Core.Protocol;
@@ -71,8 +68,8 @@ namespace MQTTnet.Core.Tests
private MqttClient ConnectTestClient(string clientId, MqttApplicationMessage willMessage, MqttServer server) private MqttClient ConnectTestClient(string clientId, MqttApplicationMessage willMessage, MqttServer server)
{ {
var adapterA = new TestMqttClientAdapter(); var adapterA = new TestMqttCommunicationAdapter();
var adapterB = new TestMqttClientAdapter(); var adapterB = new TestMqttCommunicationAdapter();
adapterA.Partner = adapterB; adapterA.Partner = adapterB;
adapterB.Partner = adapterA; adapterB.Partner = adapterA;
@@ -111,51 +108,4 @@ namespace MQTTnet.Core.Tests
Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount); Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount);
} }
} }
public class TestMqttClientAdapter : IMqttCommunicationAdapter
{
private readonly BlockingCollection<MqttBasePacket> _incomingPackets = new BlockingCollection<MqttBasePacket>();
public TestMqttClientAdapter Partner { get; set; }
public async Task ConnectAsync(MqttClientOptions options, TimeSpan timeout)
{
await Task.FromResult(0);
}
public async Task DisconnectAsync()
{
await Task.FromResult(0);
}
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout)
{
ThrowIfPartnerIsNull();
Partner.SendPacketInternal(packet);
await Task.FromResult(0);
}
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout)
{
ThrowIfPartnerIsNull();
return await Task.Run(() => _incomingPackets.Take());
}
private void SendPacketInternal(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
_incomingPackets.Add(packet);
}
private void ThrowIfPartnerIsNull()
{
if (Partner == null)
{
throw new InvalidOperationException("Partner is not set.");
}
}
}
} }
@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: Guid("a7ff0c91-25de-4ba6-b39e-f54e8dadf1cc")] [assembly: Guid("a7ff0c91-25de-4ba6-b39e-f54e8dadf1cc")]
[assembly: AssemblyVersion("2.1.0.4")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("2.1.0.4")] [assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,56 @@
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Packets;
namespace MQTTnet.Core.Tests
{
public class TestMqttCommunicationAdapter : IMqttCommunicationAdapter
{
private readonly BlockingCollection<MqttBasePacket> _incomingPackets = new BlockingCollection<MqttBasePacket>();
public TestMqttCommunicationAdapter Partner { get; set; }
public async Task ConnectAsync(MqttClientOptions options, TimeSpan timeout)
{
await Task.FromResult(0);
}
public async Task DisconnectAsync()
{
await Task.FromResult(0);
}
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout)
{
ThrowIfPartnerIsNull();
Partner.SendPacketInternal(packet);
await Task.FromResult(0);
}
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout)
{
ThrowIfPartnerIsNull();
return await Task.Run(() => _incomingPackets.Take());
}
private void SendPacketInternal(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
_incomingPackets.Add(packet);
}
private void ThrowIfPartnerIsNull()
{
if (Partner == null)
{
throw new InvalidOperationException("Partner is not set.");
}
}
}
}
@@ -35,6 +35,39 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|AnyCPU'">
<OutputPath>bin\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Any CPU\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Any CPU\</OutputPath>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -47,14 +80,14 @@
<None Include="App.config" /> <None Include="App.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{99c884f3-b4b9-417d-aa92-dc7dd1c4cfee}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\Frameworks\MQTTnet.NetFramework\MQTTnet.NetFramework.csproj"> <ProjectReference Include="..\..\Frameworks\MQTTnet.NetFramework\MQTTnet.NetFramework.csproj">
<Project>{a480ef90-0eaa-4d9a-b271-47a9c47f6f7d}</Project> <Project>{a480ef90-0eaa-4d9a-b271-47a9c47f6f7d}</Project>
<Name>MQTTnet.NetFramework</Name> <Name>MQTTnet.NetFramework</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{2ecb99e4-72d0-4c23-99ba-93d511d3967d}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+3 -1
View File
@@ -33,7 +33,9 @@ namespace MQTTnet.TestMqttClient
{ {
var options = new MqttClientOptions var options = new MqttClientOptions
{ {
Server = "localhost" Server = "localhost",
ClientId = "XYZ",
CleanSession = true
}; };
var client = new MqttClientFactory().CreateMqttClient(options); var client = new MqttClientFactory().CreateMqttClient(options);
@@ -31,6 +31,40 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|AnyCPU'">
<OutputPath>bin\Any CPU\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Any CPU\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Any CPU|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Any CPU\</OutputPath>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -43,14 +77,14 @@
<None Include="App.config" /> <None Include="App.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\Frameworks\MQTTnet.NetFramework\MQTTnet.NetFramework.csproj"> <ProjectReference Include="..\..\Frameworks\MQTTnet.NetFramework\MQTTnet.NetFramework.csproj">
<Project>{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}</Project> <Project>{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}</Project>
<Name>MQTTnet.NetFramework</Name> <Name>MQTTnet.NetFramework</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj">
<Project>{2ecb99e4-72d0-4c23-99ba-93d511d3967d}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>