├── .gitattributes ├── .gitignore ├── LICENSE.txt ├── ProtocolGateway.Standard.sln ├── ProtocolGateway.sln ├── ProtocolGateway.sln.DotSettings ├── README.md ├── RELEASE_NOTES.md ├── SECURITY.md ├── build.cmd ├── docs └── DeveloperGuide.md ├── host ├── ProtocolGateway.Host.Cloud.Service │ ├── GCSettingsManagement.ps1 │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProtocolGateway.Host.Cloud.Service.csproj │ ├── RoleEnvironmentSettingsProvider.cs │ ├── Startup.cmd │ ├── WorkerRole.cs │ ├── app.config │ └── packages.config ├── ProtocolGateway.Host.Cloud │ ├── ProtocolGateway.Host.Cloud.ServiceContent │ │ └── diagnostics.wadcfgx │ ├── ProtocolGateway.Host.Cloud.ccproj │ ├── ServiceConfiguration.Cloud.cscfg │ ├── ServiceConfiguration.Local.cscfg │ └── ServiceDefinition.csdef ├── ProtocolGateway.Host.Common │ ├── AcceptLimiter.cs │ ├── AcceptLimiterTlsReleaseHandler.cs │ ├── Bootstrapper.cs │ ├── BootstrapperEventSource.cs │ ├── MqttPacketPayloadCompressionHandler.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProtocolGateway.Host.Common.NetStandard.csproj │ ├── ProtocolGateway.Host.Common.csproj │ ├── app.config │ └── packages.config ├── ProtocolGateway.Host.Console.NetStandard │ ├── ConsoleEventListener.cs │ ├── Program.cs │ ├── ProtocolGateway.Host.Console.NetStandard.csproj │ └── appSettings.json ├── ProtocolGateway.Host.Console │ ├── App.config │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProtocolGateway.Host.Console.csproj │ ├── appSettings.config.user │ └── packages.config ├── ProtocolGateway.Host.Fabric.FrontEnd │ ├── App.config │ ├── FrontEnd.cs │ ├── PackageRoot │ │ ├── Code │ │ │ ├── InstallDotNet48.ps1 │ │ │ ├── setup.cmd │ │ │ └── setup.ps1 │ │ ├── Config │ │ │ ├── FrontEnd.AzureState.json │ │ │ ├── FrontEnd.IoTHubClient.json │ │ │ ├── FrontEnd.Mqtt.json │ │ │ ├── FrontEnd.json │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProtocolGateway.Host.Fabric.FrontEnd.csproj │ ├── configuration │ │ ├── AzureSessionStateConfiguration.cs │ │ ├── GatewayConfiguration.cs │ │ ├── IoTHubConfiguration.cs │ │ ├── MqttServiceConfiguration.cs │ │ └── ServiceFabricConfigurationProvider.cs │ ├── logging │ │ ├── Logger.cs │ │ └── ServiceLogger.cs │ ├── mqtt │ │ └── MqttCommunicationListener.cs │ └── packages.config ├── ProtocolGateway.Host.Fabric │ ├── ApplicationPackageRoot │ │ └── ApplicationManifest.xml │ ├── ApplicationParameters │ │ ├── Cloud.xml │ │ ├── Local.1Node.xml │ │ └── Local.5Node.xml │ ├── ProtocolGateway.Host.Fabric.sfproj │ ├── PublishProfiles │ │ └── Cloud.xml │ ├── Scripts │ │ └── Deploy-FabricApplication.ps1 │ ├── app.config │ └── packages.config ├── Walkthrough.md ├── deploy.ps1 ├── fabricsetup │ └── ProtocolGateway.Host.FabricSetup.CounterSetup │ │ ├── App.config │ │ ├── Program.cs │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── ProtocolGateway.Host.FabricSetup.CounterSetup.csproj │ │ └── logging │ │ └── StartupLogger.cs ├── fabricshared │ ├── ProtocolGateway.Host.Fabric.FabricShared.Configuration │ │ ├── ConfigurationChangedEventArgs.cs │ │ ├── ConfigurationProvider.cs │ │ ├── IConfigurationProvider.cs │ │ ├── Properties │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Resources.Designer.cs │ │ │ └── Resources.resx │ │ ├── ProtocolGateway.Host.Fabric.FabricShared.Configuration.csproj │ │ ├── app.config │ │ └── packages.config │ ├── ProtocolGateway.Host.Fabric.FabricShared.Health │ │ ├── HealthReporter.cs │ │ ├── MetricReporter.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── ProtocolGateway.Host.Fabric.FabricShared.Health.csproj │ │ └── packages.config │ ├── ProtocolGateway.Host.Fabric.FabricShared.Logging │ │ ├── ExceptionExtensions.cs │ │ ├── ILogger.cs │ │ ├── IServiceLogger.cs │ │ ├── LoggerBase.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── ProtocolGateway.Host.Fabric.FabricShared.Logging.csproj │ │ ├── ServiceLoggerBase.cs │ │ └── packages.config │ └── ProtocolGateway.Host.Fabric.FabricShared.Security │ │ ├── CertificateUtilities.cs │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── ProtocolGateway.Host.Fabric.FabricShared.Security.csproj │ │ └── SecureStringExtensions.cs └── shared │ └── protocol-gateway.contoso.com.pfx ├── src ├── ProtocolGateway.Core │ ├── AppConfigSettingsProvider.cs │ ├── ConfigManagerReader.cs │ ├── ConfigurationErrorsException.cs │ ├── ConfigurationExtensionReader.cs │ ├── ErrorCode.cs │ ├── Extensions │ │ └── TaskExtensions.cs │ ├── IAppConfigReader.cs │ ├── ISettingsProvider.cs │ ├── Identity │ │ ├── IDeviceIdentity.cs │ │ ├── IDeviceIdentityProvider.cs │ │ └── UnauthenticatedDeviceIdentity.cs │ ├── Instrumentation │ │ ├── AveragePerformanceCounter.cs │ │ ├── CommonEventSource.cs │ │ ├── EmptyPerformanceCounter.cs │ │ ├── EmptyPerformanceCounterManager.cs │ │ ├── IPerformanceCounter.cs │ │ ├── IPerformanceCounterManager.cs │ │ ├── PerformanceCounterCategoryInfo.cs │ │ ├── PerformanceCounters.cs │ │ ├── SafePerformanceCounter.cs │ │ └── WindowsPerformanceCounterManager.cs │ ├── Messaging │ │ ├── IBatchAwareMessagingServiceClient.cs │ │ ├── IMessage.cs │ │ ├── IMessagingBridge.cs │ │ ├── IMessagingChannel.cs │ │ ├── IMessagingServiceClient.cs │ │ ├── IMessagingSource.cs │ │ ├── Message.cs │ │ └── MessagingException.cs │ ├── Mqtt │ │ ├── AckPendingMessageState.cs │ │ ├── ChannelMessageProcessingException.cs │ │ ├── CompletionPendingMessageState.cs │ │ ├── IMessageProcessor.cs │ │ ├── IPacketReference.cs │ │ ├── MessageAsyncProcessor.cs │ │ ├── MessageAsyncProcessorBase.cs │ │ ├── MessageBatchAsyncProcessor.cs │ │ ├── MessageFeedbackChannel.cs │ │ ├── MessagePropertyNames.cs │ │ ├── MessageTypes.cs │ │ ├── MessagingBridgeFactoryFunc.cs │ │ ├── MqttAdapter.cs │ │ ├── Persistence │ │ │ ├── IQoS2MessageDeliveryState.cs │ │ │ ├── IQos2StatePersistenceProvider.cs │ │ │ ├── ISessionState.cs │ │ │ ├── ISessionStatePersistenceProvider.cs │ │ │ ├── ISubscription.cs │ │ │ ├── TransientSessionState.cs │ │ │ ├── TransientSessionStatePersistenceProvider.cs │ │ │ └── TransientSubscription.cs │ │ ├── RequestAckPairProcessor.cs │ │ ├── Settings.cs │ │ ├── TemplateParameters.cs │ │ └── Util.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ └── Friends.cs │ ├── ProtocolGateway.Core.NetStandard.csproj │ ├── ProtocolGateway.Core.csproj │ ├── ProtocolGatewayException.cs │ ├── UriPathTemplate.cs │ ├── app.config │ └── packages.config ├── ProtocolGateway.IotHubClient │ ├── AuthenticationScope.cs │ ├── CommandReceiver.cs │ ├── DeviceClientRetryPolicy.cs │ ├── Extensions.cs │ ├── IMessageDispatcher.cs │ ├── IotHubBridge.cs │ ├── IotHubClientMessage.cs │ ├── IotHubClientSettings.cs │ ├── IotHubDeviceIdentity.cs │ ├── KeyDeviceIdentityProvider.cs │ ├── MethodHandler.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ └── Friends.cs │ ├── ProtocolGateway.IotHubClient.NetStandard.csproj │ ├── ProtocolGateway.IotHubClient.csproj │ ├── SasTokenDeviceIdentityProvider.cs │ ├── SendMessageOutcome.cs │ ├── TelemetrySender.cs │ ├── TopicHandling.cs │ ├── app.config │ └── packages.config ├── ProtocolGateway.Providers.CloudStorage │ ├── BlobSessionState.cs │ ├── BlobSessionStatePersistenceProvider.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProtocolGateway.Providers.CloudStorage.NetStandard.csproj │ ├── ProtocolGateway.Providers.CloudStorage.csproj │ ├── StorageBufferManager.cs │ ├── Subscription.cs │ ├── TableMessageDeliveryState.cs │ ├── TableQos2StatePersistenceProvider.cs │ ├── app.config │ └── packages.config └── SharedAssemblyInfo.cs └── test ├── ProtocolGateway.Client.NetStandard ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── ProtocolGateway.Client.NetStandard.csproj ├── ProtocolGateway.Tests.Load ├── App.config ├── ConsoleLoggingHandler.cs ├── DeviceRunner.cs ├── EnumerableExtensions.cs ├── IdProvider.cs ├── OccasionalTelemetryRunner.cs ├── Options.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── ProtocolGateway.Tests.Load.csproj ├── RunnerConfiguration.cs ├── RunnerHost.cs ├── StableTelemetryRunner.cs ├── TaskExtensions.cs └── packages.config └── ProtocolGateway.Tests ├── ChannelExtensions.cs ├── DiagnosticsTests.cs ├── EndToEndTests.cs ├── Extensions ├── ByteBufferExtensions.cs └── TaskExtensions.cs ├── MqttTopicMatchingTests.cs ├── Properties └── AssemblyInfo.cs ├── ProtocolGateway.Tests.csproj ├── ReadListeningHandler.cs ├── XUnitLoggingHandler.cs ├── XUnitOutputSink.cs ├── app.config ├── appSettings.config.user ├── mqttTopicConversion.config.user ├── packages.config └── tlscert.pfx /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.cs text=auto diff=csharp 17 | *.vb text=auto 18 | *.resx text=auto 19 | *.c text=auto 20 | *.cpp text=auto 21 | *.cxx text=auto 22 | *.h text=auto 23 | *.hxx text=auto 24 | *.py text=auto 25 | *.rb text=auto 26 | *.java text=auto 27 | *.html text=auto 28 | *.htm text=auto 29 | *.css text=auto 30 | *.scss text=auto 31 | *.sass text=auto 32 | *.less text=auto 33 | *.js text=auto 34 | *.lisp text=auto 35 | *.clj text=auto 36 | *.sql text=auto 37 | *.php text=auto 38 | *.lua text=auto 39 | *.m text=auto 40 | *.asm text=auto 41 | *.erl text=auto 42 | *.fs text=auto 43 | *.fsx text=auto 44 | *.hs text=auto 45 | 46 | *.csproj text=auto 47 | *.vbproj text=auto 48 | *.fsproj text=auto 49 | *.dbproj text=auto 50 | *.sln text=auto eol=crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Oo]bj/ 2 | [Bb]in/ 3 | TestResults/ 4 | .nuget/ 5 | _ReSharper.*/ 6 | *.exe 7 | packages/ 8 | artifacts/ 9 | PublishProfiles/ 10 | csx/ 11 | *.user 12 | *.suo 13 | *.cache 14 | *.docstates 15 | _ReSharper.* 16 | nuget.exe 17 | *net45.csproj 18 | *net451.csproj 19 | *k10.csproj 20 | *.psess 21 | *.vsp 22 | .vs/ 23 | *.pidb 24 | *.userprefs 25 | *DS_Store 26 | *.ncrunchsolution 27 | *.*sdf 28 | *.ipch 29 | *.sln.ide 30 | *.lock.json 31 | *.db 32 | .idea.*/ 33 | .vscode/* 34 | secrets/ 35 | host/ProtocolGateway.Host.Fabric/pkg/* -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation 2 | All rights reserved. 3 | 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | #### 3.0.0 July 24, 2019 2 | - Change the way `MqttAdapter` handles transient sessions. `MqttAdapter.ProcessPendingSubscriptionChanges` will now always call `ISessionStatePersistenceProvider.SetAsync` irrespective of the session being transient or not. State handling of transient sessions is now left to the implementation of '`ISessionStatePersistenceProvider` 3 | - `BlobSessionStatePersistenceProvider.SetAsync` will return instead of throwing if the state is transient 4 | 5 | #### 1.0.1 March 12 6 | - Azure Table QoS 2 persistence provider uses proper query API to retrieve only relevant row. 7 | - QoS 2 persistence provider API is modified to work with SequenceNumber instead of MessageId. 8 | - Azure Blob session state persistence provider is modified to update ETag value on in-memory session state object to allow saving it later on without any issue. 9 | - 14 least significant bits are used when converting SequenceNumber into PacketId. 10 | - `IMessage.SequenceNumber` type is changed to ulong. 11 | 12 | #### 1.0.0 March 03 13 | - `IQos2StatePersistenceProvider` now accepts device identity to scope messages in flight to device level. 14 | - `IAuthenticationProvider` has been renamed into `IDeviceIdentityProvider` and the API has changed to allow for a flexible interaction between device identity source and other protocol gateway components. 15 | - `ITopicNameRouter` has been renamed into `IMessageRouter` and the API generalized to work with the message as a whole. 16 | - `IDeviceClient` has been renamed into `IMessagingServiceClient` to better reflect the purpose of the component. `IMessagingFactory` was introduced and message exchange with `IMessagingServiceClient` is done using `IMessage` objects. 17 | - Issues #23, #26, #27, #28, #33 have been addressed. 18 | - Microsoft Azure IoT SDK specific components have been moved to `ProtocolGateway.IotHubClient` project. 19 | - Components are now released as 3 nuget packages according to certain dependencies (Azure Storage, Azure IoT SDK): 20 | - `Microsoft.Azure.Devices.ProtocolGateway.Core`, 21 | - `Microsoft.Azure.Devices.ProtocolGateway.IotHubClient`, 22 | - `Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage`. 23 | - Renamed `samples` into `host` throughout the solution. 24 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | cd %~dp0 3 | 4 | SETLOCAL 5 | SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe 6 | 7 | IF EXIST %CACHED_NUGET% goto vsvarssetup 8 | echo Downloading latest version of NuGet.exe... 9 | IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet 10 | @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://www.nuget.org/nuget.exe' -OutFile '%CACHED_NUGET%'" 11 | 12 | :vsvarssetup 13 | if not defined VS120COMNTOOLS goto build 14 | if not exist "%VS120COMNTOOLS%\VsDevCmd.bat" goto build 15 | call "%VS120COMNTOOLS%\VsDevCmd.bat" 16 | 17 | :build 18 | %CACHED_NUGET% restore 19 | msbuild ProtocolGateway.sln -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Cloud.Service/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | 11 | [assembly: AssemblyTitle("Microsoft.Azure.Devices.ProtocolGateway.Cloud.Host")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("Microsoft.Azure.Devices.ProtocolGateway.Cloud.Host")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | 28 | [assembly: Guid("ad7f0c70-3558-42be-a423-ddaeabe879fc")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | 41 | [assembly: AssemblyVersion("1.0.0.0")] 42 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Cloud.Service/RoleEnvironmentSettingsProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Cloud.Service 5 | { 6 | using Microsoft.Azure.Devices.ProtocolGateway; 7 | using Microsoft.WindowsAzure.ServiceRuntime; 8 | 9 | public class RoleEnvironmentSettingsProvider : ISettingsProvider 10 | { 11 | public bool TryGetSetting(string name, out string value) 12 | { 13 | try 14 | { 15 | value = RoleEnvironment.GetConfigurationSettingValue(name); 16 | return true; 17 | } 18 | catch (RoleEnvironmentException) 19 | { 20 | value = default(string); 21 | return false; 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Cloud.Service/Startup.cmd: -------------------------------------------------------------------------------- 1 | REM ********************************************************* 2 | REM 3 | REM Copyright (c) Microsoft. All rights reserved. 4 | REM This code is licensed under the Microsoft Public License. 5 | REM THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | REM ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | REM IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | REM PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | REM 10 | REM ********************************************************* 11 | 12 | REM Check if the script is running in the Azure emulator and if so do not run 13 | if "%IsEmulated%"=="true" goto :PastGC 14 | 15 | if "%UseServerGC%"=="False" goto :ValidateBackground 16 | if "%UseServerGC%"=="0" goto :ValidateBackground 17 | set UseServerGC="True" 18 | 19 | :ValidateBackground 20 | if "%UseBackgroundGC%"=="False" goto :SetGC 21 | if "%UseBackgroundGC%"=="0" goto :SetGC 22 | set UseBackgroundGC="True" 23 | 24 | :SetGC 25 | PowerShell.exe -executionpolicy unrestricted -command ".\GCSettingsManagement.ps1" -serverGC %UseServerGC% -backgroundGC %UseBackgroundGC% 26 | 27 | :PastGC 28 | netsh int ipv4 set dynamicport tcp start=1025 num=64511 29 | netsh int ipv4 show dynamicport tcp 30 | 31 | exit /b -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Cloud/ServiceConfiguration.Cloud.cscfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Cloud/ServiceConfiguration.Local.cscfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Cloud/ServiceDefinition.csdef: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/AcceptLimiter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Common 5 | { 6 | using System.Threading; 7 | using DotNetty.Transport.Channels; 8 | 9 | /// 10 | /// Controls connection accept rate based on number of concurrent connections going through throttled initialization phase 11 | /// 12 | sealed class AcceptLimiter : ChannelHandlerAdapter 13 | { 14 | IChannelHandlerContext capturedContext; 15 | long available; 16 | 17 | public AcceptLimiter(long capacity) 18 | { 19 | this.available = capacity; 20 | } 21 | 22 | public override void ChannelActive(IChannelHandlerContext context) 23 | { 24 | this.capturedContext = context; 25 | base.ChannelActive(context); 26 | context.Read(); 27 | } 28 | 29 | public override void ChannelRead(IChannelHandlerContext context, object message) 30 | { 31 | if (Volatile.Read(ref this.available) > 0) 32 | { 33 | context.Read(); 34 | } 35 | base.ChannelRead(context, message); 36 | } 37 | 38 | public void Claim() => Interlocked.Decrement(ref this.available); 39 | 40 | public void ReleaseClaim() 41 | { 42 | Interlocked.Increment(ref this.available); 43 | this.capturedContext?.Read(); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/AcceptLimiterTlsReleaseHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Common 5 | { 6 | using DotNetty.Handlers.Tls; 7 | using DotNetty.Transport.Channels; 8 | 9 | sealed class AcceptLimiterTlsReleaseHandler : ChannelHandlerAdapter 10 | { 11 | readonly AcceptLimiter limiter; 12 | bool claimReturned; 13 | 14 | public AcceptLimiterTlsReleaseHandler(AcceptLimiter limiter) 15 | { 16 | this.limiter = limiter; 17 | } 18 | 19 | public override void ChannelActive(IChannelHandlerContext context) 20 | { 21 | this.limiter.Claim(); 22 | base.ChannelActive(context); 23 | } 24 | 25 | public override void ChannelInactive(IChannelHandlerContext context) 26 | { 27 | this.ReleaseClaim(); 28 | base.ChannelInactive(context); 29 | } 30 | 31 | public override void UserEventTriggered(IChannelHandlerContext context, object evt) 32 | { 33 | if (evt is TlsHandshakeCompletionEvent tls) // TLS handshake is done so we return claim 34 | { 35 | this.ReleaseClaim(); 36 | context.Channel.Pipeline.Remove(this); 37 | } 38 | base.UserEventTriggered(context, evt); 39 | } 40 | 41 | void ReleaseClaim() 42 | { 43 | if (!this.claimReturned) 44 | { 45 | this.claimReturned = true; 46 | this.limiter.ReleaseClaim(); 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/BootstrapperEventSource.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Common 5 | { 6 | using System; 7 | using System.Diagnostics.Tracing; 8 | 9 | [EventSource( 10 | Name = "IoT-ProtocolGateway-Bootstrapper", 11 | Guid = "e29735c9-6796-4228-ac96-9db40faB697a")] 12 | public class BootstrapperEventSource : EventSource 13 | { 14 | const int VerboseEventId = 1; 15 | const int InfoEventId = 2; 16 | const int WarningEventId = 3; 17 | const int ErrorEventId = 4; 18 | 19 | public static readonly BootstrapperEventSource Log = new BootstrapperEventSource(); 20 | 21 | BootstrapperEventSource() 22 | { 23 | } 24 | 25 | public bool IsVerboseEnabled => this.IsEnabled(EventLevel.Verbose, EventKeywords.None); 26 | 27 | public bool IsInfoEnabled => this.IsEnabled(EventLevel.Informational, EventKeywords.None); 28 | 29 | public bool IsWarningEnabled => this.IsEnabled(EventLevel.Warning, EventKeywords.None); 30 | 31 | public bool IsErrorEnabled => this.IsEnabled(EventLevel.Error, EventKeywords.None); 32 | 33 | [Event(VerboseEventId, Level = EventLevel.Verbose)] 34 | public void Verbose(string message, string info) => this.WriteEvent(VerboseEventId, message, info); 35 | 36 | [Event(InfoEventId, Level = EventLevel.Informational)] 37 | public void Info(string message, string info) => this.WriteEvent(InfoEventId, message, info); 38 | 39 | [NonEvent] 40 | public void Warning(string message) => this.Warning(message, string.Empty); 41 | 42 | [NonEvent] 43 | public void Warning(string message, Exception exception) => this.Warning(message, exception?.ToString() ?? string.Empty); 44 | 45 | [Event(WarningEventId, Level = EventLevel.Warning)] 46 | public void Warning(string message, string exception) => this.WriteEvent(WarningEventId, message, exception); 47 | 48 | [NonEvent] 49 | public void Error(string message, Exception exception) => this.Error(message, exception?.ToString() ?? string.Empty); 50 | 51 | [Event(ErrorEventId, Level = EventLevel.Error)] 52 | public void Error(string message, string exception) => this.WriteEvent(ErrorEventId, message, exception); 53 | } 54 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/MqttPacketPayloadCompressionHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Common 5 | { 6 | using System.Diagnostics.Contracts; 7 | using System.IO; 8 | using System.IO.Compression; 9 | using System.Threading.Tasks; 10 | using DotNetty.Buffers; 11 | using DotNetty.Codecs.Mqtt.Packets; 12 | using DotNetty.Common.Utilities; 13 | using DotNetty.Transport.Channels; 14 | 15 | public class MqttPacketPayloadCompressionHandler : ChannelHandlerAdapter 16 | { 17 | public override void ChannelRead(IChannelHandlerContext context, object message) 18 | { 19 | var packet = message as PublishPacket; 20 | if (packet != null) 21 | { 22 | IByteBuffer result = ApplyCompression(packet.Payload, CompressionMode.Decompress); 23 | packet.Payload = result; 24 | } 25 | context.FireChannelRead(message); 26 | } 27 | 28 | public override Task WriteAsync(IChannelHandlerContext context, object message) 29 | { 30 | var packet = message as PublishPacket; 31 | if (packet != null) 32 | { 33 | IByteBuffer result = ApplyCompression(packet.Payload, CompressionMode.Compress); 34 | packet.Payload = result; 35 | } 36 | return context.WriteAsync(message); 37 | } 38 | 39 | static IByteBuffer ApplyCompression(IByteBuffer buffer, CompressionMode compressionMode) 40 | { 41 | try 42 | { 43 | using (var outputStream = new MemoryStream()) 44 | { 45 | using (var gzipStream = new GZipStream(outputStream, compressionMode, true)) 46 | { 47 | buffer.ReadBytes(gzipStream, buffer.ReadableBytes); 48 | } 49 | 50 | Contract.Assert(outputStream.Length <= int.MaxValue); 51 | 52 | #if NETSTANDARD1_3 53 | return Unpooled.WrappedBuffer(outputStream.ToArray()); 54 | #else 55 | return Unpooled.WrappedBuffer(outputStream.GetBuffer(), 0, (int)outputStream.Length); 56 | #endif 57 | } 58 | } 59 | finally 60 | { 61 | ReferenceCountUtil.Release(buffer); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | 11 | [assembly: AssemblyTitle("Microsoft.Azure.Devices.ProtocolGateway.Host.Common")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("Microsoft.Azure.Devices.ProtocolGateway.Host.Common")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | 28 | [assembly: Guid("6cc530d5-d1c6-4d14-88fb-b5b29d646cf8")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | 41 | [assembly: AssemblyVersion("1.0.0.0")] 42 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/ProtocolGateway.Host.Common.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard1.3 5 | Microsoft.Azure.Devices.ProtocolGateway.Host.Common 6 | Microsoft.Azure.Devices.ProtocolGateway.Host.Common 7 | Library 8 | 1.6.1 9 | ProtocolGateway.Host.Common 10 | ProtocolGateway.Host.Common 11 | 1.0.0.0 12 | Copyright © Microsoft 2015 13 | Microsoft.Azure.Devices.ProtocolGateway.Host.Common 14 | Copyright © 2015 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Common/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Console.NetStandard/ConsoleEventListener.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Console.NetStandard 5 | { 6 | using System.Diagnostics.Tracing; 7 | using System.Text; 8 | 9 | class ConsoleEventListener : EventListener 10 | { 11 | protected override void OnEventWritten(EventWrittenEventArgs eventData) 12 | { 13 | StringBuilder payload = new StringBuilder(); 14 | foreach (object p in eventData.Payload) 15 | { 16 | payload.Append("[" + p + "]"); 17 | } 18 | System.Console.WriteLine("EventId: {0}, Level: {1}, Message: {2}, Payload: {3} , EventName: {4}", eventData.EventId, eventData.Level, eventData.Message, payload.ToString(), eventData.EventName); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Console.NetStandard/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace ProtocolGateway.Host.Console.NetStandard 5 | { 6 | using System; 7 | using System.Diagnostics.Tracing; 8 | using System.IO; 9 | using System.Security.Cryptography.X509Certificates; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using DotNetty.Common.Internal.Logging; 13 | using Microsoft.Azure.Devices.ProtocolGateway; 14 | using Microsoft.Azure.Devices.ProtocolGateway.Instrumentation; 15 | using Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence; 16 | using ProtocolGateway.Host.Common; 17 | 18 | class Program 19 | { 20 | static void Main(string[] args) 21 | { 22 | int threadCount = Environment.ProcessorCount; 23 | if (args.Length > 0) 24 | { 25 | threadCount = int.Parse(args[0]); 26 | } 27 | 28 | var eventListener = new ConsoleEventListener(); 29 | 30 | eventListener.EnableEvents(BootstrapperEventSource.Log, EventLevel.Verbose); 31 | eventListener.EnableEvents(CommonEventSource.Log, EventLevel.Verbose); 32 | eventListener.EnableEvents(DefaultEventSource.Log, EventLevel.Verbose); 33 | 34 | try 35 | { 36 | var cts = new CancellationTokenSource(); 37 | 38 | var certificate = new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "protocol-gateway.contoso.com.pfx"), "password"); 39 | var settingsProvider = new AppConfigSettingsProvider(); 40 | ISessionStatePersistenceProvider sessionStateProvider = new TransientSessionStatePersistenceProvider(); 41 | 42 | var bootstrapper = new Bootstrapper(settingsProvider, sessionStateProvider, null); 43 | Task.Run(() => bootstrapper.RunAsync(certificate, threadCount, cts.Token), cts.Token); 44 | 45 | while (true) 46 | { 47 | string input = Console.ReadLine(); 48 | if (input != null && input.ToLowerInvariant() == "exit") 49 | { 50 | break; 51 | } 52 | } 53 | 54 | cts.Cancel(); 55 | bootstrapper.CloseCompletion.Wait(TimeSpan.FromSeconds(20)); 56 | } 57 | finally 58 | { 59 | eventListener.Dispose(); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Console.NetStandard/ProtocolGateway.Host.Console.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | exe 5 | netcoreapp1.1 6 | 7 | exe 8 | 9 | ProtocolGateway.Host.Console 10 | ProtocolGateway.Host.Console 11 | 1.0.0.0 12 | 13 | 14 | 15 | bin\Debug 16 | 17 | 18 | 19 | 20 | PreserveNewest 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | PreserveNewest 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Console.NetStandard/appSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "appSettings": { 3 | "MaxPendingInboundAcknowledgements": 16, 4 | "DeviceReceiveAckTimeout": "00:00:00", 5 | "MaxInboundMessageSize": "262144", 6 | "ConnectArrivalTimeout": "00:01:00", 7 | "MaxKeepAliveTimeout": "00:10:00", 8 | "RetainPropertyName": "mqtt-retain", 9 | "DupPropertyName": "mqtt-dup", 10 | "QoSPropertyName": "mqtt-qos", 11 | "IotHubClient.ConnectionString": "", 12 | "IotHubClient.MaxPendingInboundMessages": 10, 13 | "IotHubClient.MaxPendingOutboundMessages": 10, 14 | "IotHubClient.DefaultPublishToClientQoS": 1, 15 | "IotHubClient.MaxOutboundRetransmissionCount": 2, 16 | "IotHubClient.ConnectionPoolSize": 400, 17 | "IotHubClient.ConnectionIdleTimeout": "00:03:30", 18 | "BlobSessionStatePersistenceProvider.StorageConnectionString": "UseDevelopmentStorage=true", 19 | "BlobSessionStatePersistenceProvider.StorageContainerName": "mqtt-sessions", 20 | "TableQos2StatePersistenceProvider.StorageConnectionString": "UseDevelopmentStorage=true", 21 | "TableQos2StatePersistenceProvider.StorageTableName": "mqttqos2" 22 | }, 23 | "mqttTopicNameConversion": { 24 | "InboundTemplates": [ 25 | "devices/{deviceId}/messages/events/" 26 | 27 | ], 28 | "OutboundTemplates": [ 29 | "devices/{deviceId}/messages/devicebound" 30 | ] 31 | } 32 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Console/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Resources; 6 | 7 | [assembly: NeutralResourcesLanguage("en-US")] 8 | [assembly: AssemblyMetadata("Serviceable", "True")] -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Console/appSettings.config.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Code/InstallDotNet48.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | 3 | <# 4 | .DESCRIPTION 5 | Install .Net Framework 4.8 6 | #> 7 | 8 | 9 | [CmdletBinding()] 10 | Param( 11 | [switch]$norestart 12 | ) 13 | 14 | Set-StrictMode -Version Latest 15 | 16 | $logFile = Join-Path $env:TEMP -ChildPath "InstallNetFx48ScriptLog.txt" 17 | 18 | # Check if the latest NetFx472 version exists 19 | $netFxKey = Get-ItemProperty -Path "HKLM:\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\" -ErrorAction Ignore 20 | 21 | if($netFxKey -and $netFxKey.Release -ge 528040) { 22 | "$(Get-Date): The machine already has NetFx 4.8 or later version installed." | Tee-Object -FilePath $logFile -Append 23 | exit 0 24 | } 25 | 26 | # Download the latest NetFx472 27 | $setupFileSourceUri = "https://download.visualstudio.microsoft.com/download/pr/7afca223-55d2-470a-8edc-6a1739ae3252/c9b8749dd99fc0d4453b2a3e4c37ba16/ndp48-web.exe" 28 | $setupFileLocalPath = Join-Path $env:TEMP -ChildPath "ndp48-web.exe" 29 | 30 | "$(Get-Date): Start to download NetFx 4.8 to $setupFileLocalPath." | Tee-Object -FilePath $logFile -Append 31 | 32 | if(Test-Path $setupFileLocalPath) 33 | { 34 | Remove-Item -Path $setupFileLocalPath -Force 35 | } 36 | 37 | $webClient = New-Object System.Net.WebClient 38 | 39 | $retry = 0 40 | 41 | do 42 | { 43 | try { 44 | $webClient.DownloadFile($setupFileSourceUri, $setupFileLocalPath) 45 | break 46 | } 47 | catch [Net.WebException] { 48 | $retry++ 49 | 50 | if($retry -gt 3) { 51 | "$(Get-Date): Download failed as the network connection issue. Exception detail: $_" | Tee-Object -FilePath $logFile -Append 52 | break 53 | } 54 | 55 | $waitInSecond = $retry * 30 56 | "$(Get-Date): It looks the Internet network is not available now. Simply wait for $waitInSecond seconds and try again." | Tee-Object -FilePath $logFile -Append 57 | Start-Sleep -Second $waitInSecond 58 | } 59 | } while ($true) 60 | 61 | 62 | if(!(Test-Path $setupFileLocalPath)) 63 | { 64 | "$(Get-Date): Failed to download NetFx 4.8 setup package." | Tee-Object -FilePath $logFile -Append 65 | exit -1 66 | } 67 | 68 | # Install NetFx48 69 | $setupLogFilePath = Join-Path $env:TEMP -ChildPath "NetFx48SetupLog.txt" 70 | if($norestart) { 71 | $arguments = "/q /norestart /serialdownload /log $setupLogFilePath" 72 | } 73 | else { 74 | $arguments = "/q /serialdownload /log $setupLogFilePath" 75 | } 76 | "$(Get-Date): Start to install NetFx 4.8" | Tee-Object -FilePath $logFile -Append 77 | $process = Start-Process -FilePath $setupFileLocalPath -ArgumentList $arguments -Wait -PassThru 78 | 79 | if(-not $process) { 80 | "$(Get-Date): Install NetFx failed." | Tee-Object -FilePath $logFile -Append 81 | exit -1 82 | } 83 | else { 84 | $exitCode = $process.ExitCode 85 | 86 | # 0, 1641 and 3010 indicate success. See https://msdn.microsoft.com/en-us/library/ee390831(v=vs.110).aspx for detail. 87 | if($exitCode -eq 0 -or $exitCode -eq 1641 -or $exitCode -eq 3010) { 88 | "$(Get-Date): Install NetFx succeeded with exit code : $exitCode." | Tee-Object -FilePath $logFile -Append 89 | exit 0 90 | } 91 | else { 92 | "$(Get-Date): Install NetFx failed with exit code : $exitCode." | Tee-Object -FilePath $logFile -Append 93 | exit -1 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Code/setup.cmd: -------------------------------------------------------------------------------- 1 | powershell.exe -ExecutionPolicy Bypass -Command ".\setup.ps1" -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Code/setup.ps1: -------------------------------------------------------------------------------- 1 | .\ProtocolGateway.Host.FabricSetup.CounterSetup.exe 2 | 3 | # Installing .NET Framework 4.8 4 | #.\InstallDotNet48.ps1 -norestart 5 | 6 | # Tweaking SChannel User Reference Context settings to prevent excessive contention on SChannel context lookup 7 | $listCount = 4096; 8 | $lockCount = 256; 9 | $props = Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL; 10 | $oldListCount = $props.UserContextListCount; 11 | $oldLockCount = $props.UserContextLockCount; 12 | if ($oldListCount -ne $listCount -or $oldLockCount -ne $lockCount) { 13 | Write-Output "Updating SChannel settings. Old UserContextListCount: $oldListCount; old UserContextLockCount: $oldLockCount; New UserContextListCount: $listCount; new UserContextLockCount: $lockCount."; 14 | New-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL -Name UserContextListCount -PropertyType "DWord" -Value $listCount -Force; 15 | New-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL -Name UserContextLockCount -PropertyType "DWord" -Value $lockCount -Force; 16 | Restart-Computer; 17 | } 18 | else { 19 | Write-Output "SChannel settings are up to date" 20 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Config/FrontEnd.AzureState.json: -------------------------------------------------------------------------------- 1 | { 2 | "BlobConnectionString": "UseDevelopmentStorage=true;", 3 | "ContainerName": "mqtt-sessions", 4 | "TableConnectionString": "UseDevelopmentStorage=true;", 5 | "TableName": "mqttqos2" 6 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Config/FrontEnd.IoTHubClient.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionString": "TODO: IoT Hub connection string to connect to", 3 | "DefaultPublishToClientQoS": "1", 4 | "MaxPendingInboundMessages": "16", 5 | "MaxPendingOutboundMessages": "10", 6 | "MaxOutboundRetransmissionCount": "-1", 7 | "ConnectionPoolSize": "400", 8 | "ConnectionIdleTimeout": "00:03:30" 9 | } 10 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Config/FrontEnd.Mqtt.json: -------------------------------------------------------------------------------- 1 | { 2 | "RetainPropertyName": "mqtt-retain", 3 | "DupPropertyName": "mqtt-dup", 4 | "QoSPropertyName": "mqtt-qos", 5 | "MqttQoSStateProvider": "AzureStorage", 6 | "ConnectArrivalTimeout": "00:05:00", 7 | "MaxPendingInboundAcknowledgements": "16", 8 | "MaxInboundMessageSize": "262144", 9 | "MaxKeepAliveTimeout": "00:10:00" 10 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Config/FrontEnd.json: -------------------------------------------------------------------------------- 1 | { 2 | "X509Identifier": "protocol-gateway.contoso.com.pfx", 3 | "X509Credential": "password", 4 | "X509Location": "Data", 5 | "EndPointName": "ServiceEndpoint", 6 | "HealthReportInterval": "00:00:15", 7 | "MetricsReportInterval": "00:00:15" 8 | } -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/Config/Settings.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/PackageRoot/ServiceManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | setup.cmd 23 | CodePackage 24 | 25 | 26 | 27 | 28 | ProtocolGateway.Host.Fabric.FrontEnd.exe 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/Program.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FrontEnd 2 | { 3 | #region Using Clauses 4 | using System; 5 | using System.Threading; 6 | using Microsoft.ServiceFabric.Services.Runtime; 7 | using FabricShared.Logging; 8 | using Logging; 9 | #endregion 10 | 11 | /// 12 | /// Host application to register service fabric types 13 | /// 14 | static class Program 15 | { 16 | /// 17 | /// This is the entry point of the service host process. 18 | /// 19 | static void Main() 20 | { 21 | const string SystemName = @"Protocol Gateway Front End"; 22 | const string ComponentName = @"Registration Application"; 23 | 24 | ILogger logger = new Logger(SystemName); 25 | Guid traceId = Guid.NewGuid(); 26 | 27 | try 28 | { 29 | logger.Informational(traceId, ComponentName, "Initializing FrontEndType."); 30 | ServiceRuntime.RegisterServiceAsync("FrontEndType", context => new FrontEnd(traceId, SystemName, context)).GetAwaiter().GetResult(); 31 | logger.Informational(traceId, ComponentName, "Services registered."); 32 | 33 | // Prevents this host process from terminating so services keep running. 34 | Thread.Sleep(Timeout.Infinite); 35 | } 36 | catch (Exception e) 37 | { 38 | logger.Critical(traceId, ComponentName, "Error during registration of type {0}.", new object[] { typeof(FrontEnd).Name }, e); 39 | throw; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProtocolGateway.Host.Fabric.FrontEnd")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProtocolGateway.Host.Fabric.FrontEnd")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a4701342-633a-4eee-ba50-7384156bebbd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/configuration/AzureSessionStateConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FrontEnd.Configuration 2 | { 3 | /// 4 | /// Configuration details for the Azure storage provider 5 | /// 6 | public class AzureSessionStateConfiguration 7 | { 8 | /// 9 | /// Azure Storage connection string to be used by the BlobSessionStatePersistenceProvider to store MQTT session state data. Default value for 10 | /// Console sample and Cloud sample's Local configuration: UseDevelopmentStorage=true . For Cloud deployment the default value is a connection 11 | /// string to the specified storage account. 12 | /// 13 | public string BlobConnectionString { get; set; } 14 | 15 | /// 16 | /// Azure Storage Blob Container Name to be used by the BlobSessionStatePersistenceProvider to store MQTT session state data. Default value: mqtt-sessions 17 | /// 18 | public string ContainerName { get; set; } 19 | 20 | /// 21 | /// Azure Storage connection string to be used by TableQos2StatePersistenceProvider to store QoS 2 delivery information. Default value for Console sample and 22 | /// Cloud sample's Local configuration: UseDevelopmentStorage=true . For Cloud deployment the default value is a connection string to specified storage account. 23 | /// 24 | public string TableConnectionString { get; set; } 25 | 26 | /// 27 | /// Azure Storage Table name to be used by the TableQos2StatePersistenceProvider to store QoS 2 delivery information. Default value: mqttqos2 28 | /// 29 | public string TableName { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/configuration/GatewayConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FrontEnd.Configuration 2 | { 3 | #region Using Clauses 4 | using System; 5 | #endregion 6 | 7 | /// 8 | /// Configuration information for the protocol gateway 9 | /// 10 | public sealed class GatewayConfiguration 11 | { 12 | /// 13 | /// The thumbprint of the certificate if in keyvault or local, file name if data store to use for server side MQTTS 14 | /// 15 | public string X509Identifier { get; set; } 16 | 17 | 18 | /// Todo: Secure this 19 | 20 | /// 21 | /// The file password, client credential for key vault for the server certificate 22 | /// 23 | public string X509Credential { get; set; } 24 | 25 | /// 26 | /// The location that the certificate is stored in 27 | /// 28 | public CertificateLocation X509Location { get; set; } 29 | 30 | /// 31 | /// The name of the endpoint in the endpoint list 32 | /// 33 | public string EndPointName { get; set; } 34 | 35 | /// 36 | /// The interval to report health at 37 | /// 38 | public TimeSpan HealthReportInterval { get; set; } 39 | 40 | /// 41 | /// The interval to report capacity metrics at 42 | /// 43 | public TimeSpan MetricsReportInterval { get; set; } 44 | 45 | /// 46 | /// The possible locations for the X509 certificate to be stored 47 | /// 48 | public enum CertificateLocation 49 | { 50 | LocalStore = 0, 51 | Data = 1, 52 | KeyVault = 2 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/configuration/IoTHubConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FrontEnd.Configuration 2 | { 3 | #region Using Clauses 4 | using System; 5 | #endregion 6 | 7 | /// 8 | /// IoTHubClient configuration data 9 | /// 10 | public class IoTHubConfiguration 11 | { 12 | /// 13 | /// REQUIRED Connection string to IoT hub. Defines the connection parameters when connecting to IoT hub on behalf of devices. By default, 14 | /// the protocol gateway will override the credentials from the connection string with the device credentials provided when a device connects 15 | /// to the gateway. No default value. 16 | /// 17 | public string ConnectionString { get; set; } 18 | 19 | /// 20 | /// Default Quality of Service to be used when publishing a message to a device. Can be overridden by adding a property on the message in 21 | /// IoT hub with the name defined by the QoSProperty setting and the value of the desired QoS level. Supported values are: 0, 1, 2. 22 | /// Default value: 1 (at least once) 23 | /// 24 | public int DefaultPublishToClientQoS { get; set; } 25 | 26 | /// 27 | /// Maximum allowed number of received messages pending processing. Protocol gateway will stop reading data from the device connection once 28 | /// it reaches MaxPendingInboundMessages and will restart only after the number of pending messages becomes lower than MaxPendingInboundMessages. 29 | /// Default value: 16 30 | /// 31 | public int MaxPendingInboundMessages { get; set; } 32 | 33 | /// 34 | /// Maximum allowed number of published device-bound messages pending acknowledgement. Protocol gateway will stop receiving messages from IoT hub 35 | /// once it reaches MaxPendingOutboundMessages and will restart only after the number of messages pending acknowledgement becomes lower than 36 | /// MaxPendingOutboundMessages. The number of messages is calculated as a sum of all unacknowledged messages: PUBLISH (QoS 1) pending PUBACK, 37 | /// PUBLISH (QoS 2) pending PUBREC, and PUBREL pending PUBCOMP. Default value: 1 38 | /// 39 | public int MaxPendingOutboundMessages { get; set; } 40 | 41 | /// 42 | /// If specified, maximum number of attempts to deliver a device-bound message. Messages that reach the limit of allowed delivery attempts will be 43 | /// rejected. If not specified or is less than or equal to 0, no maximum number of delivery attempts is imposed. Default value: -1 44 | /// 45 | public int MaxOutboundRetransmissionCount { get; set; } 46 | 47 | /// 48 | /// The maximum connection count to the IoT Hub 49 | /// 50 | public int ConnectionPoolSize { get; set; } 51 | 52 | /// 53 | /// The connection timeout for a client connected to the IoT Hub 54 | /// 55 | public TimeSpan ConnectionIdleTimeout { get; set; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric.FrontEnd/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/ApplicationPackageRoot/ApplicationManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/ApplicationParameters/Cloud.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/ApplicationParameters/Local.1Node.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/ApplicationParameters/Local.5Node.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/PublishProfiles/Cloud.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /host/ProtocolGateway.Host.Fabric/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /host/Walkthrough.md: -------------------------------------------------------------------------------- 1 | # Samples Walkthrough 2 | 3 | Samples consist of the following projects: 4 | 5 | - **Gateway.Samples.Common** contains classes and resources used by both Cloud and Console samples. Here you can find bootstrapper and samples of additional handlers. 6 | - **Gateway.Samples.Console** showcases a console application host for Azure IoT Gateway. 7 | - **Gateway.Samples.Cloud.Host** serves as a host for cloud sample's entry point. It wires up the Bootstrapper to run in Azure Cloud Service. 8 | - **Gateway.Samples.Cloud** is a cloud project for packaging and deploying Gateway.Samples.Cloud.Host to Azure. 9 | 10 | ## Components 11 | 12 | ### Bootstrapper 13 | 14 | Bootstrapper showcases a configuration and lifecycle control for Azure IoT Gateway. 15 | -------------------------------------------------------------------------------- /host/fabricsetup/ProtocolGateway.Host.FabricSetup.CounterSetup/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /host/fabricsetup/ProtocolGateway.Host.FabricSetup.CounterSetup/Program.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.FabricSetup.CounterSetup 2 | { 3 | #region Using Clauses 4 | using System; 5 | using Microsoft.Azure.Devices.ProtocolGateway.Instrumentation; 6 | using logging; 7 | #endregion 8 | 9 | /// 10 | /// Used to register performance counters and the appropriate category for the service fabric front end service 11 | /// 12 | class Program 13 | { 14 | /// 15 | /// Primary entry point for the program 16 | /// 17 | /// 18 | static void Main(string[] args) 19 | { 20 | const string ComponentName = @"Front End Setup"; 21 | 22 | var logger = new StartupLogger("Protocol Gateway Setup"); 23 | Guid traceId = Guid.NewGuid(); 24 | 25 | try 26 | { 27 | logger.Informational(traceId, ComponentName, "Launched."); 28 | PerformanceCounters.RegisterCountersIfRequired(); 29 | logger.Informational(traceId, ComponentName, "Completed without exceptions."); 30 | } 31 | catch (Exception e) 32 | { 33 | logger.Critical(traceId, ComponentName, "Could not prepare the environment due to an error.", null, e); 34 | throw; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /host/fabricsetup/ProtocolGateway.Host.FabricSetup.CounterSetup/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProtocolGateway.Host.FabricSetup.CounterSetup")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProtocolGateway.Host.FabricSetup.CounterSetup")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("07885ae0-1df1-4ba5-8197-f3514a06bdd3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Configuration/ConfigurationChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FabricShared.Configuration 2 | { 3 | #region Using Clauses 4 | using System; 5 | #endregion 6 | 7 | /// 8 | /// Configuration class changed event arguments. 9 | /// 10 | /// 11 | public sealed class ConfigurationChangedEventArgs : EventArgs where TConfiguration : class 12 | { 13 | #region Properties 14 | /// 15 | /// Name of the changed configuration. 16 | /// 17 | public string Name { get; } 18 | 19 | /// 20 | /// Configuration class instance. 21 | /// 22 | public TConfiguration CurrentConfiguration { get; } 23 | 24 | /// 25 | /// Configuration class instance. 26 | /// 27 | public TConfiguration NewConfiguration { get; } 28 | 29 | /// 30 | /// The name of the configuration 31 | /// 32 | public string ConfigurationName { get; } 33 | #endregion 34 | #region Constructors 35 | /// 36 | /// ConfigurationClassChangeEventArgs constructor. 37 | /// 38 | /// Name of the changed configuration. 39 | /// Current configuration instance of type TConfiguration. 40 | /// New configuration instance of type TConfiguration. 41 | /// The name of the configuration. 42 | public ConfigurationChangedEventArgs(string name, TConfiguration currentConfig, TConfiguration newConfig, string configurationName) 43 | { 44 | this.Name = name; 45 | this.CurrentConfiguration = currentConfig; 46 | this.NewConfiguration = newConfig; 47 | this.ConfigurationName = configurationName; 48 | } 49 | #endregion 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Configuration/IConfigurationProvider.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FabricShared.Configuration 2 | { 3 | #region Using Clauses 4 | using System.Security; 5 | #endregion 6 | 7 | /// 8 | /// ConfigurationProvider interface. 9 | /// 10 | public interface IConfigurationProvider where TConfiguration : class 11 | { 12 | #region Properties 13 | /// 14 | /// Gets the configuration settings values. 15 | /// 16 | TConfiguration Config { get; } 17 | 18 | /// 19 | /// The name of the configuration to load. This will be appended to the name of the service when looking for the file (e.g. FrontEnd.Name.json) 20 | /// 21 | string ConfigurationName { get; } 22 | #endregion 23 | #region Methods 24 | /// 25 | /// Get a configuration value 26 | /// 27 | /// Name of the configuration item. Key value is case sensitive. 28 | /// Default value to return. 29 | /// Value of the configuration setting or the default value. 30 | string GetConfigurationString(string key, string defaultValue); 31 | 32 | /// 33 | /// Gets an encrypted configuration value. 34 | /// 35 | /// Name of the configuration item. Key value is case sensitive. 36 | /// Default value to return. 37 | /// Value of the configuration setting. 38 | SecureString GetEncryptedConfigurationString(string key, string defaultValue); 39 | 40 | /// 41 | /// Gets a configuration value of the specified type 42 | /// 43 | /// Name of the configuration item. Key value is case sensitive. 44 | /// Default value to return. 45 | /// Value of the configuration item or the default value. 46 | T GetConfigurationValue(string key, T defaultValue); 47 | 48 | /// 49 | /// Gets a configuration value of the specified type from a JSON string 50 | /// 51 | /// Name of the configuration item. Key value is case sensitive. 52 | /// Default value to return. 53 | /// Value of the configuration item or the default value. 54 | T GetConfigurationJsonValue(string key, T defaultValue); 55 | #endregion 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Configuration/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProtocolGateway.Host.Fabric.FabricShared.Configuration")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProtocolGateway.Host.Fabric.FabricShared.Configuration")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("cedd1f60-e803-476a-9f73-3814cdce3c4b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Configuration/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Configuration/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Health/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProtocolGateway.Host.Fabric.FabricShared.Health")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProtocolGateway.Host.Fabric.FabricShared.Health")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("443e59d8-9395-41f1-aa8f-4895a734c2aa")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Health/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Logging/ExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FabricShared.Logging 2 | { 3 | #region Using Clauses 4 | using System; 5 | using System.Text; 6 | #endregion 7 | 8 | /// 9 | /// Extension class used for flattening exceptions 10 | /// 11 | public static class ExceptionExtensions 12 | { 13 | #region Public Methods 14 | /// 15 | /// Flattens the exceptions error message including all inner exceptions. 16 | /// 17 | /// The exception to flatten. 18 | /// A string representing the exceptions error message concatenated with the inner exception messages. 19 | public static string Flatten(this Exception exception) 20 | { 21 | string flatException = string.Empty; 22 | 23 | if (exception != null) 24 | { 25 | var aggregateException = exception as AggregateException; 26 | 27 | flatException = aggregateException == null ? FlattenException(exception) : FlattenAggregateException(aggregateException); 28 | } 29 | 30 | return flatException; 31 | } 32 | #endregion 33 | #region Private Methods 34 | /// 35 | /// Flattens a standard exception object. 36 | /// 37 | /// The exception to be flattened. 38 | /// A string that concatenates all inner exception messages as well. 39 | static string FlattenException(Exception exception) 40 | { 41 | var builder = new StringBuilder(exception.Message); 42 | 43 | if (exception.InnerException != null) 44 | { 45 | var aggregateException = exception.InnerException as AggregateException; 46 | 47 | builder.AppendLine(aggregateException == null 48 | ? FlattenException(exception.InnerException) 49 | : FlattenAggregateException(aggregateException)); 50 | } 51 | 52 | return builder.ToString(); 53 | } 54 | 55 | /// 56 | /// Flattens an aggregate exception object. 57 | /// 58 | /// An aggregate exception object to be flattened. 59 | /// A string that concatenates all inner exception messages as well. 60 | static string FlattenAggregateException(AggregateException exception) 61 | { 62 | var builder = new StringBuilder(); 63 | 64 | if (exception.InnerExceptions != null) 65 | { 66 | builder.AppendLine(exception.Message); 67 | 68 | foreach (Exception innerException in exception.InnerExceptions) 69 | { 70 | var innerAggregateException = innerException as AggregateException; 71 | 72 | builder.AppendLine(innerAggregateException != null 73 | ? FlattenAggregateException(innerAggregateException) 74 | : FlattenException(innerException)); 75 | } 76 | } 77 | 78 | return builder.ToString(); 79 | } 80 | #endregion 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Logging/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProtocolGateway.Host.Fabric.FabricShared.Logging")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProtocolGateway.Host.Fabric.FabricShared.Logging")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a2537696-fd02-40cd-b179-2df85cc52a89")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Logging/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Security/CertificateUtilities.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FabricShared.Security 2 | { 3 | #region Using Clauses 4 | using System; 5 | using System.Security; 6 | using System.Security.Cryptography.X509Certificates; 7 | #endregion 8 | 9 | /// 10 | /// Utilities associated with the X509 Certificates and their store 11 | /// 12 | public static class CertificateUtilities 13 | { 14 | #region Certificate Retrieval 15 | /// 16 | /// Retrieves an X509 Certificate from the specified store and location 17 | /// 18 | /// The certificate thumbprint 19 | /// The name of the store to retrieve the information from 20 | /// The location within the store where the certificate is located 21 | /// An X509 certificate with the specified thumbprint if available or null if not 22 | public static X509Certificate2 GetCertificate(string thumbprint, StoreName storeName, StoreLocation storeLocation) 23 | { 24 | X509Store store = null; 25 | X509Certificate2 certificate; 26 | 27 | try 28 | { 29 | store = new X509Store(storeName, storeLocation); 30 | store.Open(OpenFlags.ReadOnly); 31 | X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false); 32 | 33 | certificate = collection.Count == 0 ? null : collection[0]; 34 | } 35 | finally 36 | { 37 | store?.Close(); 38 | } 39 | 40 | return certificate; 41 | } 42 | 43 | /// 44 | /// Retrieves an X509 certificate from a password protected PFX file file 45 | /// 46 | /// The X509 certificate 47 | public static X509Certificate2 GetCertificateFromFile(string fileName, SecureString password) 48 | { 49 | return new X509Certificate2(fileName, password); 50 | } 51 | 52 | /// 53 | /// Retrieves an X509 certificate from a password protected PFX file file 54 | /// 55 | /// The X509 certificate 56 | public static X509Certificate2 GetCertificateFromFile(string fileName, string password) 57 | { 58 | return new X509Certificate2(fileName, password); 59 | } 60 | 61 | /// 62 | /// Retrieves an X509 certificate from key vault 63 | /// 64 | /// The X509 certificate 65 | public static X509Certificate2 GetCertificateFromKeyVault(string fileName, SecureString password) 66 | { 67 | throw new NotImplementedException(); 68 | } 69 | #endregion 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Security/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ProtocolGateway.Host.Fabric.FabricShared.Security")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProtocolGateway.Host.Fabric.FabricShared.Security")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("1cb06c3e-3d1c-4fd4-95e9-037b4361303a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Security/ProtocolGateway.Host.Fabric.FabricShared.Security.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1CB06C3E-3D1C-4FD4-95E9-037B4361303A} 8 | Library 9 | Properties 10 | ProtocolGateway.Host.Fabric.FabricShared.Security 11 | ProtocolGateway.Host.Fabric.FabricShared.Security 12 | v4.5.1 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | bin\x64\Debug\ 36 | DEBUG;TRACE 37 | full 38 | x64 39 | prompt 40 | MinimumRecommendedRules.ruleset 41 | 42 | 43 | bin\x64\Release\ 44 | TRACE 45 | true 46 | pdbonly 47 | x64 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 68 | -------------------------------------------------------------------------------- /host/fabricshared/ProtocolGateway.Host.Fabric.FabricShared.Security/SecureStringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace ProtocolGateway.Host.Fabric.FabricShared.Security 2 | { 3 | #region Using Clauses 4 | using System; 5 | using System.Runtime.InteropServices; 6 | using System.Security; 7 | #endregion 8 | 9 | /// 10 | /// Contains common secure string handling methods. 11 | /// 12 | public static class SecureStringExtensions 13 | { 14 | #region Extension Methods 15 | /// 16 | /// Creates a secure string based on the contents of the provided string. 17 | /// 18 | /// The string holding the contents of the secure string. 19 | /// A populated secure string that contains the value specified in the string parameter. 20 | public static SecureString GetSecureString(this string value) 21 | { 22 | var results = new SecureString(); 23 | 24 | foreach (char character in value) 25 | { 26 | results.AppendChar(character); 27 | } 28 | 29 | return results; 30 | } 31 | 32 | /// 33 | /// Creates a CLR string based on the provided secure string value. 34 | /// 35 | /// The secure string that contains the value to be placed in the CLR string. 36 | /// 37 | public static string SecureStringToString(this SecureString value) 38 | { 39 | string plainValue = null; 40 | 41 | if (value != null) 42 | { 43 | IntPtr valuePtr = IntPtr.Zero; 44 | 45 | try 46 | { 47 | valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value); 48 | 49 | plainValue = Marshal.PtrToStringUni(valuePtr); 50 | } 51 | finally 52 | { 53 | if (valuePtr != IntPtr.Zero) Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); 54 | } 55 | } 56 | 57 | return plainValue; 58 | } 59 | #endregion 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /host/shared/protocol-gateway.contoso.com.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-iot-protocol-gateway/4f6d32d1116a2cbc50fd608c8a5b44f5a1037971/host/shared/protocol-gateway.contoso.com.pfx -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/AppConfigSettingsProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | public class AppConfigSettingsProvider : ISettingsProvider 7 | { 8 | IAppConfigReader configStrategy; 9 | 10 | public AppConfigSettingsProvider() 11 | { 12 | #if NETSTANDARD1_3 13 | this.configStrategy = new ConfigurationExtensionReader(); 14 | #else 15 | this.configStrategy = new ConfigManagerReader(); 16 | #endif 17 | } 18 | public bool TryGetSetting(string name, out string value) 19 | { 20 | return configStrategy.TryGetSetting(name, out value); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/ConfigManagerReader.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | using System.Configuration; 7 | 8 | class ConfigManagerReader : IAppConfigReader 9 | { 10 | public bool TryGetSetting(string name, out string value) 11 | { 12 | string[] values = ConfigurationManager.AppSettings.GetValues(name); 13 | if (values == null || values.Length == 0) 14 | { 15 | value = default(string); 16 | return false; 17 | } 18 | 19 | value = values[0]; 20 | return true; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/ConfigurationErrorsException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | using System; 7 | 8 | public class ConfigurationErrorsException : Exception 9 | { 10 | public ConfigurationErrorsException() 11 | { 12 | } 13 | 14 | public ConfigurationErrorsException(string message) : base(message) 15 | { 16 | } 17 | 18 | public ConfigurationErrorsException(string message, Exception innerException) : base(message, innerException) 19 | { 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/ConfigurationExtensionReader.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | using Microsoft.Extensions.Configuration; 7 | 8 | public class ConfigurationExtensionReader : IAppConfigReader 9 | { 10 | static readonly IConfiguration Config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); 11 | 12 | public bool TryGetSetting(string name, out string value) 13 | { 14 | IConfigurationSection appsettings = Config.GetSection("AppSettings"); 15 | value = appsettings.GetSection(name).Value; 16 | if (value == null) 17 | { 18 | value = default(string); 19 | return false; 20 | } 21 | 22 | return true; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/ErrorCode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | public enum ErrorCode 7 | { 8 | InvalidErrorCode = 0, 9 | 10 | //BadRequest - 400 11 | InvalidPubAckOrder = 400001, 12 | GenericTimeOut = 400002, 13 | InvalidOperation = 400003, 14 | NotSupported = 400004, 15 | KeepAliveTimedOut = 400005, 16 | ConnectionTimedOut = 400006, 17 | ConnectExpected = 400007, 18 | UnResolvedSendingClient = 400008, 19 | UnknownQosType = 400009, 20 | QoSLevelNotSupported = 400010, 21 | ExactlyOnceQosNotSupported = 400011, 22 | UnknownPacketType = 400012, 23 | DuplicateConnectReceived = 400013, 24 | 25 | AuthenticationFailed = 401000, 26 | 27 | //ClientClosedRequest - 499 28 | ChannelClosed = 499001, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Extensions/TaskExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Extensions 5 | { 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | public static class TaskExtensions 10 | { 11 | public static void OnFault(this Task task, Action faultAction) 12 | { 13 | switch (task.Status) 14 | { 15 | case TaskStatus.RanToCompletion: 16 | case TaskStatus.Canceled: 17 | break; 18 | case TaskStatus.Faulted: 19 | faultAction(task); 20 | break; 21 | default: 22 | task.ContinueWith(faultAction, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); 23 | break; 24 | } 25 | } 26 | 27 | public static void OnFault(this Task task, Action faultAction, object state) 28 | { 29 | switch (task.Status) 30 | { 31 | case TaskStatus.RanToCompletion: 32 | case TaskStatus.Canceled: 33 | break; 34 | case TaskStatus.Faulted: 35 | faultAction(task, state); 36 | break; 37 | default: 38 | task.ContinueWith(faultAction, state, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); 39 | break; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/IAppConfigReader.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | interface IAppConfigReader 13 | { 14 | bool TryGetSetting(string name, out string value); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Identity/IDeviceIdentity.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Identity 5 | { 6 | public interface IDeviceIdentity 7 | { 8 | bool IsAuthenticated { get; } 9 | 10 | string Id { get; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Identity/IDeviceIdentityProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Identity 5 | { 6 | using System.Net; 7 | using System.Threading.Tasks; 8 | 9 | public interface IDeviceIdentityProvider 10 | { 11 | Task GetAsync(string clientId, string username, string password, EndPoint clientAddress); 12 | } 13 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Identity/UnauthenticatedDeviceIdentity.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Identity 5 | { 6 | using System; 7 | 8 | public sealed class UnauthenticatedDeviceIdentity : IDeviceIdentity 9 | { 10 | public static IDeviceIdentity Instance { get; } = new UnauthenticatedDeviceIdentity(); 11 | 12 | UnauthenticatedDeviceIdentity() 13 | { 14 | } 15 | 16 | public bool IsAuthenticated => false; 17 | 18 | public string Id 19 | { 20 | get { throw new InvalidOperationException("Accessing identity of device while authentication failed."); } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/AveragePerformanceCounter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | using DotNetty.Common; 7 | 8 | public sealed class AveragePerformanceCounter 9 | { 10 | readonly IPerformanceCounter countCounter; 11 | readonly IPerformanceCounter baseCounter; 12 | 13 | public AveragePerformanceCounter(IPerformanceCounter countCounter, IPerformanceCounter baseCounter) 14 | { 15 | this.countCounter = countCounter; 16 | this.baseCounter = baseCounter; 17 | } 18 | 19 | public void Register(PreciseTimeSpan startTimestamp) 20 | { 21 | PreciseTimeSpan elapsed = PreciseTimeSpan.FromStart - startTimestamp; 22 | long elapsedMs = (long)elapsed.ToTimeSpan().TotalMilliseconds; 23 | this.countCounter.IncrementBy(elapsedMs); 24 | this.baseCounter.Increment(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/CommonEventSource.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | using System; 7 | using System.Diagnostics.Tracing; 8 | 9 | [EventSource( 10 | Name = "IoT-ProtocolGateway-Common", 11 | Guid = "06d7118e-3a71-4143-8aab-ed8cedf69e1c")] 12 | public class CommonEventSource : EventSource 13 | { 14 | const int VerboseEventId = 1; 15 | const int InfoEventId = 2; 16 | const int WarningEventId = 3; 17 | const int ErrorEventId = 4; 18 | 19 | public static readonly CommonEventSource Log = new CommonEventSource(); 20 | 21 | CommonEventSource() 22 | { 23 | } 24 | 25 | public bool IsVerboseEnabled => this.IsEnabled(EventLevel.Verbose, EventKeywords.None); 26 | 27 | public bool IsInfoEnabled => this.IsEnabled(EventLevel.Informational, EventKeywords.None); 28 | 29 | public bool IsWarningEnabled => this.IsEnabled(EventLevel.Warning, EventKeywords.None); 30 | 31 | public bool IsErrorEnabled => this.IsEnabled(EventLevel.Error, EventKeywords.None); 32 | 33 | [NonEvent] 34 | public void Verbose(string message) => this.Verbose(message, string.Empty, string.Empty); 35 | 36 | [Event(VerboseEventId, Level = EventLevel.Verbose)] 37 | public void Verbose(string message, string channelId, string deviceId) => this.WriteEvent(VerboseEventId, message, channelId, deviceId); 38 | 39 | [Event(InfoEventId, Level = EventLevel.Informational)] 40 | public void Info(string message, string channelId, string deviceId) => this.WriteEvent(InfoEventId, message, channelId, deviceId); 41 | 42 | [NonEvent] 43 | public void Warning(string message, string channelId, string deviceId) => this.Warning(message, string.Empty, channelId, deviceId); 44 | 45 | [NonEvent] 46 | public void Warning(string message, Exception exception, string channelId, string deviceId) => this.Warning(message, exception?.ToString() ?? string.Empty, channelId, deviceId); 47 | 48 | [Event(WarningEventId, Level = EventLevel.Warning)] 49 | public void Warning(string message, string exception, string channelId, string deviceId) => this.WriteEvent(WarningEventId, message, exception, channelId, deviceId); 50 | 51 | [NonEvent] 52 | public void Error(string message, Exception exception, string channelId, string deviceId) => this.Error(message, exception?.ToString() ?? string.Empty, channelId, deviceId); 53 | 54 | [Event(ErrorEventId, Level = EventLevel.Error)] 55 | public void Error(string message, string exception, string channelId, string deviceId) => this.WriteEvent(ErrorEventId, message, exception, channelId, deviceId); 56 | } 57 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/EmptyPerformanceCounter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | public sealed class EmptyPerformanceCounter : IPerformanceCounter 7 | { 8 | public long RawValue { get; set; } 9 | public string CounterName { get; private set; } 10 | 11 | public EmptyPerformanceCounter(string name) 12 | { 13 | this.CounterName = name; 14 | } 15 | 16 | public EmptyPerformanceCounter() 17 | { 18 | } 19 | 20 | public float NextValue 21 | { 22 | get { return 0; } 23 | } 24 | 25 | public void Increment() 26 | { 27 | } 28 | 29 | public void IncrementBy(long value) 30 | { 31 | } 32 | 33 | public void Decrement() 34 | { 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/EmptyPerformanceCounterManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | public class EmptyPerformanceCounterManager : IPerformanceCounterManager 7 | { 8 | public IPerformanceCounter GetCounter(string category, string name) 9 | { 10 | return new EmptyPerformanceCounter(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/IPerformanceCounter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | public interface IPerformanceCounter 7 | { 8 | long RawValue { get; set; } 9 | float NextValue { get; } 10 | void Increment(); 11 | void IncrementBy(long value); 12 | void Decrement(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/IPerformanceCounterManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | public interface IPerformanceCounterManager 7 | { 8 | IPerformanceCounter GetCounter(string category, string name); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/PerformanceCounterCategoryInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | using System.Diagnostics; 7 | 8 | public sealed class PerformanceCounterCategoryInfo 9 | { 10 | public PerformanceCounterCategoryInfo(string categoryName, PerformanceCounterCategoryType categoryType, string categoryHelp) 11 | { 12 | this.CategoryName = categoryName; 13 | this.CategoryType = categoryType; 14 | this.CategoryHelp = categoryHelp; 15 | } 16 | 17 | public string CategoryName { get; private set; } 18 | 19 | public PerformanceCounterCategoryType CategoryType { get; private set; } 20 | 21 | public string CategoryHelp { get; private set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Instrumentation/SafePerformanceCounter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Instrumentation 5 | { 6 | using System; 7 | using System.Diagnostics; 8 | 9 | public sealed class SafePerformanceCounter : IPerformanceCounter 10 | { 11 | readonly PerformanceCounter counter; 12 | 13 | public SafePerformanceCounter(PerformanceCounter counter) 14 | { 15 | this.counter = counter; 16 | } 17 | 18 | public long RawValue 19 | { 20 | get { return this.counter.RawValue; } 21 | set { this.counter.RawValue = value; } 22 | } 23 | 24 | public float NextValue 25 | { 26 | get 27 | { 28 | return this.counter.NextValue(); 29 | } 30 | } 31 | 32 | public void Increment() 33 | { 34 | try 35 | { 36 | this.counter.Increment(); 37 | } 38 | catch (Exception ex) 39 | { 40 | CommonEventSource.Log.Verbose("Failed to increment perf counter: " + ex.ToString()); 41 | } 42 | } 43 | 44 | public void IncrementBy(long value) 45 | { 46 | try 47 | { 48 | this.counter.IncrementBy(value); 49 | } 50 | catch (Exception ex) 51 | { 52 | CommonEventSource.Log.Verbose("Failed to increment perf counter: " + ex.ToString()); 53 | } 54 | } 55 | 56 | public void Decrement() 57 | { 58 | try 59 | { 60 | this.counter.Decrement(); 61 | } 62 | catch (Exception ex) 63 | { 64 | CommonEventSource.Log.Verbose("Failed to decrement perf counter: " + ex.ToString()); 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/IBatchAwareMessagingServiceClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | 9 | public interface IBatchAwareMessagingServiceClient : IMessagingServiceClient 10 | { 11 | Task SendBatchAsync(IReadOnlyCollection messages); 12 | 13 | int MaxBatchSize { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/IMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using DotNetty.Buffers; 9 | 10 | public interface IMessage : IDisposable 11 | { 12 | string Address { get; } 13 | 14 | IByteBuffer Payload { get; } 15 | 16 | string Id { get; } 17 | 18 | IDictionary Properties { get; } 19 | 20 | DateTime CreatedTimeUtc { get; } 21 | 22 | uint DeliveryCount { get; } 23 | 24 | ulong SequenceNumber { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/IMessagingBridge.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | public interface IMessagingBridge 10 | { 11 | void BindMessagingChannel(IMessagingChannel channel); 12 | 13 | bool TryResolveClient(string topicName, out IMessagingServiceClient sendingClient); 14 | 15 | Task DisposeAsync(Exception cause); 16 | } 17 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/IMessagingChannel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System; 7 | 8 | public interface IMessagingChannel 9 | { 10 | void Handle(IMessage message, IMessagingSource sender); 11 | 12 | void Close(Exception cause); 13 | 14 | event EventHandler CapabilitiesChanged; 15 | } 16 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/IMessagingServiceClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System; 7 | using System.Threading.Tasks; 8 | using DotNetty.Buffers; 9 | 10 | public interface IMessagingServiceClient 11 | { 12 | int MaxPendingMessages { get; } 13 | 14 | IMessage CreateMessage(string address, IByteBuffer payload); 15 | 16 | Task SendAsync(IMessage message); 17 | 18 | Task DisposeAsync(Exception cause); 19 | } 20 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/IMessagingSource.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | public interface IMessagingSource 10 | { 11 | void BindMessagingChannel(IMessagingChannel channel); 12 | 13 | Task CompleteAsync(string messageId); 14 | 15 | Task RejectAsync(string messageId); 16 | 17 | Task DisposeAsync(Exception cause); 18 | } 19 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/Message.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using DotNetty.Buffers; 9 | using DotNetty.Common.Utilities; 10 | 11 | public sealed class Message : IMessage 12 | { 13 | Dictionary properties; 14 | 15 | public string Address { get; set; } 16 | 17 | public IByteBuffer Payload { get; set; } 18 | 19 | public string Id { get; set; } 20 | 21 | public IDictionary Properties => this.properties ?? (this.properties = new Dictionary(3)); 22 | 23 | public DateTime CreatedTimeUtc { get; set; } 24 | 25 | public uint DeliveryCount { get; set; } 26 | 27 | public ulong SequenceNumber { get; set; } 28 | 29 | public void Dispose() 30 | { 31 | if (this.Payload != null) 32 | { 33 | ReferenceCountUtil.SafeRelease(this.Payload); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Messaging/MessagingException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 4 | { 5 | using System; 6 | 7 | public class MessagingException: Exception 8 | { 9 | 10 | public bool IsTransient { get; } 11 | 12 | public string TrackingId { get; set; } 13 | 14 | public MessagingException(string message) 15 | : this(message, false) 16 | { 17 | } 18 | 19 | public MessagingException(string message, bool isTransient) 20 | : this(message, isTransient, string.Empty) 21 | { 22 | } 23 | 24 | public MessagingException(string message, string trackingId) 25 | : this(message, false, trackingId) 26 | { 27 | } 28 | 29 | public MessagingException(string message, bool isTransient, string trackingId) 30 | : base(message) 31 | { 32 | this.IsTransient = isTransient; 33 | this.TrackingId = trackingId; 34 | } 35 | 36 | public MessagingException(string message, Exception innerException) 37 | : this(message, innerException, false) 38 | { 39 | } 40 | 41 | public MessagingException(string message, Exception innerException, bool isTransient) 42 | : this(message, innerException, isTransient, string.Empty) 43 | { 44 | } 45 | 46 | public MessagingException(string message, Exception innerException, string trackingId) 47 | : this(message, innerException, false, trackingId) 48 | { 49 | } 50 | 51 | public MessagingException(string message, Exception innerException, bool isTransient, string trackingId) 52 | : base(message, innerException) 53 | { 54 | this.IsTransient = isTransient; 55 | this.TrackingId = trackingId; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/AckPendingMessageState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | using DotNetty.Codecs.Mqtt.Packets; 7 | using DotNetty.Common; 8 | using Microsoft.Azure.Devices.ProtocolGateway.Messaging; 9 | 10 | sealed class AckPendingMessageState : IPacketReference // todo: recycle? 11 | { 12 | public AckPendingMessageState(IMessage message, IMessagingSource callback, PublishPacket packet) 13 | { 14 | this.SequenceNumber = message.SequenceNumber; 15 | this.PacketId = packet.PacketId; 16 | this.QualityOfService = packet.QualityOfService; 17 | this.FeedbackChannel = new MessageFeedbackChannel(message.Id, callback); 18 | this.StartTimestamp = PreciseTimeSpan.FromStart; 19 | } 20 | 21 | public PreciseTimeSpan StartTimestamp { get; set; } 22 | 23 | public ulong SequenceNumber { get; } 24 | 25 | public int PacketId { get; } 26 | 27 | public QualityOfService QualityOfService { get; private set; } 28 | 29 | public MessageFeedbackChannel FeedbackChannel { get; private set; } 30 | } 31 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/ChannelMessageProcessingException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | using System; 7 | using DotNetty.Transport.Channels; 8 | 9 | public class ChannelMessageProcessingException : Exception 10 | { 11 | public ChannelMessageProcessingException(Exception innerException, IChannelHandlerContext context) 12 | : base(string.Empty, innerException) 13 | { 14 | this.Context = context; 15 | } 16 | 17 | public IChannelHandlerContext Context { get; private set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/CompletionPendingMessageState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | using DotNetty.Common; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Messaging; 8 | using Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence; 9 | 10 | sealed class CompletionPendingMessageState : IPacketReference 11 | { 12 | public CompletionPendingMessageState(int packetId, IQos2MessageDeliveryState deliveryState, 13 | PreciseTimeSpan startTimestamp, MessageFeedbackChannel feedbackChannel) 14 | { 15 | this.PacketId = packetId; 16 | this.DeliveryState = deliveryState; 17 | this.StartTimestamp = startTimestamp; 18 | this.FeedbackChannel = feedbackChannel; 19 | } 20 | 21 | public int PacketId { get; } 22 | 23 | public IQos2MessageDeliveryState DeliveryState { get; private set; } 24 | 25 | public PreciseTimeSpan StartTimestamp { get; private set; } 26 | 27 | public MessageFeedbackChannel FeedbackChannel { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/IMessageProcessor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | using System.Threading.Tasks; 7 | using DotNetty.Transport.Channels; 8 | 9 | public interface IMessageProcessor 10 | { 11 | void Post(IChannelHandlerContext context, T message); 12 | 13 | int BacklogSize { get; } 14 | 15 | Task Closed { get; } 16 | 17 | void Close(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/IPacketReference.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | interface IPacketReference 7 | { 8 | int PacketId { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/MessageAsyncProcessor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | using System; 7 | using System.Threading.Tasks; 8 | using DotNetty.Transport.Channels; 9 | 10 | public sealed class MessageAsyncProcessor : MessageAsyncProcessorBase, IMessageProcessor 11 | { 12 | readonly Func processFunc; 13 | 14 | public MessageAsyncProcessor(Func processFunc) 15 | { 16 | this.processFunc = processFunc; 17 | } 18 | 19 | protected override Task ProcessAsync(IChannelHandlerContext context, T packet) => this.processFunc(context, packet); 20 | } 21 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/MessageFeedbackChannel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Messaging 5 | { 6 | using System.Threading.Tasks; 7 | 8 | public struct MessageFeedbackChannel 9 | { 10 | readonly string messageId; 11 | readonly IMessagingSource callback; 12 | 13 | public MessageFeedbackChannel(string messageId, IMessagingSource callback) 14 | { 15 | this.messageId = messageId; 16 | this.callback = callback; 17 | } 18 | 19 | public Task CompleteAsync() => this.callback.CompleteAsync(this.messageId); 20 | 21 | public Task RejectAsync() => this.callback.RejectAsync(this.messageId); 22 | } 23 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/MessagePropertyNames.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | public static class MessagePropertyNames 7 | { 8 | public const string MessageType = "MessageType"; 9 | public const string Unmatched = "Unmatched"; 10 | public const string Subject = "Subject"; 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/MessageTypes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | public static class MessageTypes 7 | { 8 | public const string Will = "Will"; 9 | } 10 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/MessagingBridgeFactoryFunc.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 9 | using Microsoft.Azure.Devices.ProtocolGateway.Messaging; 10 | 11 | public delegate Task MessagingBridgeFactoryFunc(IDeviceIdentity deviceIdentity, CancellationToken cancellationToken); 12 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/IQoS2MessageDeliveryState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System; 7 | 8 | public interface IQos2MessageDeliveryState 9 | { 10 | DateTime LastModified { get; } 11 | 12 | ulong SequenceNumber { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/IQos2StatePersistenceProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System.Threading.Tasks; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 8 | 9 | public interface IQos2StatePersistenceProvider 10 | { 11 | IQos2MessageDeliveryState Create(ulong sequenceNumber); 12 | 13 | /// 14 | /// Performs a lookup of message delivery state by packet identifier 15 | /// 16 | /// Device identity 17 | /// Packet identifier 18 | /// 19 | /// object if message was previously persisted with 20 | /// the given packet id; null - if no message could be found. 21 | /// 22 | Task GetMessageAsync(IDeviceIdentity deviceIdentity, int packetId); 23 | 24 | Task DeleteMessageAsync(IDeviceIdentity deviceIdentity, int packetId, IQos2MessageDeliveryState message); 25 | 26 | Task SetMessageAsync(IDeviceIdentity deviceIdentity, int packetId, IQos2MessageDeliveryState message); 27 | } 28 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/ISessionState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System.Collections.Generic; 7 | using DotNetty.Codecs.Mqtt.Packets; 8 | 9 | public interface ISessionState 10 | { 11 | IReadOnlyList Subscriptions { get; } 12 | 13 | bool IsTransient { get; } 14 | 15 | ISessionState Copy(); 16 | 17 | bool AddOrUpdateSubscription(string topicFilter, QualityOfService qos); 18 | 19 | bool RemoveSubscription(string topicFilter); 20 | } 21 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/ISessionStatePersistenceProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System.Threading.Tasks; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 8 | 9 | public interface ISessionStatePersistenceProvider 10 | { 11 | ISessionState Create(bool transient); 12 | 13 | Task GetAsync(IDeviceIdentity identity); 14 | 15 | Task SetAsync(IDeviceIdentity identity, ISessionState sessionState); 16 | 17 | Task DeleteAsync(IDeviceIdentity identity, ISessionState sessionState); 18 | } 19 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/ISubscription.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System; 7 | using DotNetty.Codecs.Mqtt.Packets; 8 | 9 | public interface ISubscription 10 | { 11 | DateTime CreationTime { get; } 12 | 13 | string TopicFilter { get; } 14 | 15 | QualityOfService QualityOfService { get; } 16 | 17 | ISubscription CreateUpdated(QualityOfService qos); 18 | } 19 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/TransientSessionState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using DotNetty.Codecs.Mqtt.Packets; 9 | 10 | class TransientSessionState : ISessionState 11 | { 12 | readonly List subscriptions; 13 | 14 | public TransientSessionState(bool transient) 15 | { 16 | this.IsTransient = transient; 17 | this.subscriptions = new List(); 18 | } 19 | 20 | public bool IsTransient { get; } 21 | 22 | public IReadOnlyList Subscriptions => this.subscriptions; 23 | 24 | public ISessionState Copy() 25 | { 26 | var sessionState = new TransientSessionState(this.IsTransient); 27 | sessionState.subscriptions.AddRange(this.Subscriptions); 28 | return sessionState; 29 | } 30 | 31 | public bool RemoveSubscription(string topicFilter) 32 | { 33 | int index = this.FindSubscriptionIndex(topicFilter); 34 | if (index >= 0) 35 | { 36 | this.subscriptions.RemoveAt(index); 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | public bool AddOrUpdateSubscription(string topicFilter, QualityOfService qos) 43 | { 44 | int index = this.FindSubscriptionIndex(topicFilter); 45 | 46 | if (index >= 0) 47 | { 48 | if (this.subscriptions[index].QualityOfService != qos) 49 | { 50 | this.subscriptions[index] = this.subscriptions[index].CreateUpdated(qos); 51 | return true; 52 | } 53 | } 54 | else 55 | { 56 | this.subscriptions.Add(new TransientSubscription(topicFilter, qos)); 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | int FindSubscriptionIndex(string topicFilter) 63 | { 64 | for (int i = this.subscriptions.Count - 1; i >= 0; i--) 65 | { 66 | ISubscription subscription = this.subscriptions[i]; 67 | if (subscription.TopicFilter.Equals(topicFilter, StringComparison.Ordinal)) 68 | { 69 | return i; 70 | } 71 | } 72 | return -1; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/TransientSessionStatePersistenceProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System.Threading.Tasks; 7 | using DotNetty.Common.Utilities; 8 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 9 | 10 | public sealed class TransientSessionStatePersistenceProvider : ISessionStatePersistenceProvider 11 | { 12 | public ISessionState Create(bool transient) 13 | { 14 | return new TransientSessionState(transient); 15 | } 16 | 17 | public Task GetAsync(IDeviceIdentity identity) 18 | { 19 | return Task.FromResult((ISessionState)null); 20 | } 21 | 22 | public Task SetAsync(IDeviceIdentity identity, ISessionState sessionState) 23 | { 24 | return TaskEx.Completed; 25 | } 26 | 27 | public Task DeleteAsync(IDeviceIdentity identity, ISessionState sessionState) 28 | { 29 | return TaskEx.Completed; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/Persistence/TransientSubscription.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence 5 | { 6 | using System; 7 | using System.Diagnostics.Contracts; 8 | using DotNetty.Codecs.Mqtt.Packets; 9 | 10 | public class TransientSubscription : ISubscription 11 | { 12 | public TransientSubscription(string topicFilter, QualityOfService qualityOfService) 13 | : this(DateTime.UtcNow, topicFilter, qualityOfService) 14 | { 15 | } 16 | 17 | TransientSubscription(DateTime creationTime, string topicFilter, QualityOfService qualityOfService) 18 | { 19 | this.CreationTime = creationTime; 20 | this.TopicFilter = topicFilter; 21 | this.QualityOfService = qualityOfService; 22 | } 23 | 24 | public DateTime CreationTime { get; } 25 | 26 | public string TopicFilter { get; } 27 | 28 | public QualityOfService QualityOfService { get; } 29 | 30 | [Pure] 31 | public ISubscription CreateUpdated(QualityOfService qos) => new TransientSubscription(this.CreationTime, this.TopicFilter, qos); 32 | } 33 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Mqtt/TemplateParameters.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Mqtt 5 | { 6 | public static class TemplateParameters 7 | { 8 | public const string DeviceIdTemplateParam = "deviceId"; 9 | } 10 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Resources; 6 | 7 | [assembly: AssemblyTitle("Microsoft.Azure.Devices.ProtocolGateway.Core")] 8 | [assembly: NeutralResourcesLanguage("en-US")] 9 | [assembly: AssemblyMetadata("Serviceable", "True")] -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/Properties/Friends.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Runtime.CompilerServices; 5 | 6 | [assembly: InternalsVisibleTo("Microsoft.Azure.Devices.ProtocolGateway.Tests")] -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/ProtocolGateway.Core.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard1.3;net451 5 | Microsoft.Azure.Devices.ProtocolGateway.Core 6 | Microsoft Azure IoT protocol gateway framework - Core 7 | This library contains the core components of Azure IoT protocol gateway that enables protocol translation for Azure IoT Hub. 8 | Library 9 | 1.6.1 10 | Microsoft.Azure.Devices.ProtocolGateway.Core 11 | Microsoft.Azure.Devices.ProtocolGateway.Core 12 | 2.2.2.0 13 | 2.2.2 14 | en-US 15 | Microsoft 16 | Microsoft Azure IoT protocol gateway 17 | © Microsoft Corporation. All rights reserved. 18 | Microsoft 19 | http://go.microsoft.com/fwlink/?LinkID=288890 20 | https://github.com/Azure/azure-iot-protocol-gateway/blob/master/LICENSE.txt 21 | https://github.com/Azure/azure-iot-protocol-gateway/ 22 | true 23 | Microsoft.Azure.Devices.ProtocolGateway.Core 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/ProtocolGatewayException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway 5 | { 6 | using System; 7 | 8 | public class ProtocolGatewayException : Exception 9 | { 10 | public bool IsTransient { get; } 11 | 12 | public string TrackingId { get; private set; } 13 | 14 | public ErrorCode ErrorCode { get; private set; } 15 | 16 | public ProtocolGatewayException(ErrorCode errorCode, string message) 17 | : this(errorCode, message, false) 18 | { 19 | } 20 | 21 | public ProtocolGatewayException(ErrorCode errorCode, string message, string trackingId) 22 | : this(errorCode, message, false, trackingId) 23 | { 24 | } 25 | 26 | public ProtocolGatewayException(ErrorCode errorCode, string message, bool isTransient) 27 | : this(errorCode, message, isTransient, string.Empty) 28 | { 29 | } 30 | 31 | public ProtocolGatewayException(ErrorCode errorCode, string message, bool isTransient, string trackingId) 32 | : base(message) 33 | { 34 | this.IsTransient = isTransient; 35 | this.TrackingId = trackingId; 36 | this.ErrorCode = errorCode; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Core/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/AuthenticationScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | public enum AuthenticationScope 7 | { 8 | None, 9 | SasToken, 10 | DeviceKey, 11 | HubKey 12 | } 13 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/DeviceClientRetryPolicy.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using System; 7 | using Microsoft.Azure.Devices.Client; 8 | 9 | public class DeviceClientRetryPolicy : IRetryPolicy 10 | { 11 | public static DeviceClientRetryPolicy Instance { get; } = new DeviceClientRetryPolicy(); 12 | 13 | DeviceClientRetryPolicy() 14 | { } 15 | 16 | public bool ShouldRetry(int currentRetryCount, Exception lastException, out TimeSpan retryInterval) 17 | { 18 | // No retry for now. We will tune it as we progress. 19 | retryInterval = TimeSpan.Zero; 20 | return false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/Extensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using Microsoft.Azure.Devices.Client.Exceptions; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Messaging; 8 | 9 | static class Extensions 10 | { 11 | public static MessagingException ToMessagingException(this IotHubException ex) 12 | { 13 | return new MessagingException("Error communicating with IoT Hub. Tracking id: " + ex.TrackingId, ex, ex.IsTransient, ex.TrackingId); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/IMessageDispatcher.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using System.Threading.Tasks; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Messaging; 8 | 9 | public interface IMessageDispatcher 10 | { 11 | Task SendAsync(IMessage message); 12 | } 13 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/IotHubClientMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using DotNetty.Buffers; 9 | using DotNetty.Common.Utilities; 10 | using Microsoft.Azure.Devices.ProtocolGateway.Messaging; 11 | using Message = Client.Message; 12 | 13 | public sealed class IotHubClientMessage : IMessage 14 | { 15 | readonly Message message; 16 | 17 | public IotHubClientMessage(Message message, IByteBuffer payload) 18 | { 19 | this.message = message; 20 | this.Payload = payload; 21 | } 22 | 23 | public IDictionary Properties => this.message.Properties; 24 | 25 | public string Address { get; set; } 26 | 27 | public IByteBuffer Payload { get; } 28 | 29 | public string Id => this.message.LockToken; 30 | 31 | public DateTime CreatedTimeUtc => this.message.EnqueuedTimeUtc; 32 | 33 | public uint DeliveryCount => this.message.DeliveryCount; 34 | 35 | public ulong SequenceNumber => this.message.SequenceNumber; 36 | 37 | public void Dispose() 38 | { 39 | this.message.Dispose(); 40 | if (this.Payload != null) 41 | { 42 | ReferenceCountUtil.SafeRelease(this.Payload); 43 | } 44 | } 45 | 46 | internal Message ToMessage() => this.message; 47 | } 48 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/IotHubDeviceIdentity.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 7 | 8 | public sealed class IotHubDeviceIdentity : IDeviceIdentity 9 | { 10 | string asString; 11 | string policyName; 12 | AuthenticationScope scope; 13 | 14 | public IotHubDeviceIdentity(string iotHubHostName, string deviceId) 15 | { 16 | this.IotHubHostName = iotHubHostName; 17 | this.Id = deviceId; 18 | } 19 | 20 | public string Id { get; } 21 | 22 | public bool IsAuthenticated => true; 23 | 24 | public string IotHubHostName { get; } 25 | 26 | public string PolicyName 27 | { 28 | get { return this.policyName; } 29 | private set 30 | { 31 | this.policyName = value; 32 | this.asString = null; 33 | } 34 | } 35 | 36 | public string Secret { get; private set; } 37 | 38 | public AuthenticationScope Scope 39 | { 40 | get { return this.scope; } 41 | private set 42 | { 43 | this.scope = value; 44 | this.asString = null; 45 | } 46 | } 47 | 48 | public static bool TryParse(string value, out IotHubDeviceIdentity identity) 49 | { 50 | string[] usernameSegments = value.Split('/'); 51 | if (usernameSegments.Length < 2) 52 | { 53 | identity = null; 54 | return false; 55 | } 56 | identity = new IotHubDeviceIdentity(usernameSegments[0], usernameSegments[1]); 57 | return true; 58 | } 59 | 60 | public void WithSasToken(string token) 61 | { 62 | this.Scope = AuthenticationScope.SasToken; 63 | this.Secret = token; 64 | } 65 | 66 | public void WithHubKey(string keyName, string keyValue) 67 | { 68 | this.Scope = AuthenticationScope.HubKey; 69 | this.PolicyName = keyName; 70 | this.Secret = keyValue; 71 | } 72 | 73 | public void WithDeviceKey(string keyValue) 74 | { 75 | this.Scope = AuthenticationScope.DeviceKey; 76 | this.Secret = keyValue; 77 | } 78 | 79 | public override string ToString() 80 | { 81 | if (this.asString == null) 82 | { 83 | string policy = string.IsNullOrEmpty(this.PolicyName) ? "" : this.PolicyName; 84 | this.asString = $"{this.Id} [IotHubHostName: {this.IotHubHostName}; PolicyName: {policy}; Scope: {this.Scope}]"; 85 | } 86 | return this.asString; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/KeyDeviceIdentityProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using System; 7 | using System.Net; 8 | using System.Threading.Tasks; 9 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 10 | 11 | public sealed class KeyDeviceIdentityProvider : IDeviceIdentityProvider 12 | { 13 | public Task GetAsync(string clientId, string username, string password, EndPoint clientAddress) 14 | { 15 | IotHubDeviceIdentity deviceIdentity; 16 | if (!IotHubDeviceIdentity.TryParse(username, out deviceIdentity) || !clientId.Equals(deviceIdentity.Id, StringComparison.Ordinal)) 17 | { 18 | return Task.FromResult(UnauthenticatedDeviceIdentity.Instance); 19 | } 20 | deviceIdentity.WithDeviceKey(password); 21 | return Task.FromResult(deviceIdentity); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Resources; 6 | 7 | [assembly: AssemblyTitle("Microsoft.Azure.Devices.ProtocolGateway.IotHubClient")] 8 | [assembly: NeutralResourcesLanguage("en-US")] 9 | [assembly: AssemblyMetadata("Serviceable", "True")] -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/Properties/Friends.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Runtime.CompilerServices; 5 | 6 | [assembly: InternalsVisibleTo("Microsoft.Azure.Devices.ProtocolGateway.Tests")] -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/ProtocolGateway.IotHubClient.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard1.3;net451 5 | Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 6 | Microsoft Azure IoT protocol gateway framework - IoT Hub client 7 | This library contains Azure IoT Hub specific components of Azure IoT protocol gateway that enables protocol translation for Azure IoT Hub. 8 | Library 9 | 1.6.1 10 | Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 11 | Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 12 | 2.0.1.0 13 | 2.0.1 14 | en-US 15 | Microsoft 16 | Microsoft Azure IoT protocol gateway 17 | © Microsoft Corporation. All rights reserved. 18 | Microsoft 19 | http://go.microsoft.com/fwlink/?LinkID=288890 20 | https://github.com/Azure/azure-iot-protocol-gateway/blob/master/LICENSE.txt 21 | https://github.com/Azure/azure-iot-protocol-gateway/ 22 | true 23 | Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/SasTokenDeviceIdentityProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | using System; 7 | using System.Net; 8 | using System.Threading.Tasks; 9 | using Microsoft.Azure.Devices.ProtocolGateway.Identity; 10 | 11 | public sealed class SasTokenDeviceIdentityProvider : IDeviceIdentityProvider 12 | { 13 | public Task GetAsync(string clientId, string username, string password, EndPoint clientAddress) 14 | { 15 | IotHubDeviceIdentity deviceIdentity; 16 | if (!IotHubDeviceIdentity.TryParse(username, out deviceIdentity) || !clientId.Equals(deviceIdentity.Id, StringComparison.Ordinal)) 17 | { 18 | return Task.FromResult(UnauthenticatedDeviceIdentity.Instance); 19 | } 20 | deviceIdentity.WithSasToken(password); 21 | return Task.FromResult(deviceIdentity); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/SendMessageOutcome.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.IotHubClient 5 | { 6 | public enum SendMessageOutcome 7 | { 8 | Completed, 9 | Rejected, 10 | } 11 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.IotHubClient/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Providers.CloudStorage/BlobSessionState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Runtime.Serialization; 9 | using DotNetty.Codecs.Mqtt.Packets; 10 | using Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence; 11 | 12 | class BlobSessionState : ISessionState 13 | { 14 | [DataMember(Name = "subscriptions")] // todo: name casing seems to be ignored by the serializer 15 | readonly List subscriptions; 16 | 17 | public BlobSessionState(bool transient) 18 | { 19 | this.IsTransient = transient; 20 | this.subscriptions = new List(); 21 | } 22 | 23 | [IgnoreDataMember] 24 | public bool IsTransient { get; } 25 | 26 | public IReadOnlyList Subscriptions => this.subscriptions; 27 | 28 | [IgnoreDataMember] 29 | public string ETag { get; set; } 30 | 31 | public ISessionState Copy() 32 | { 33 | var sessionState = new BlobSessionState(this.IsTransient); 34 | sessionState.ETag = this.ETag; 35 | sessionState.subscriptions.AddRange(this.Subscriptions); 36 | return sessionState; 37 | } 38 | 39 | public bool RemoveSubscription(string topicFilter) 40 | { 41 | int index = this.FindSubscriptionIndex(topicFilter); 42 | if (index >= 0) 43 | { 44 | this.subscriptions.RemoveAt(index); 45 | return true; 46 | } 47 | return false; 48 | } 49 | 50 | public bool AddOrUpdateSubscription(string topicFilter, QualityOfService qos) 51 | { 52 | int index = this.FindSubscriptionIndex(topicFilter); 53 | 54 | if (index >= 0) 55 | { 56 | if (this.subscriptions[index].QualityOfService != qos) 57 | { 58 | this.subscriptions[index] = this.subscriptions[index].CreateUpdated(qos); 59 | return true; 60 | } 61 | } 62 | else 63 | { 64 | this.subscriptions.Add(new Subscription(topicFilter, qos)); 65 | return true; 66 | } 67 | return false; 68 | } 69 | 70 | int FindSubscriptionIndex(string topicFilter) 71 | { 72 | for (int i = this.subscriptions.Count - 1; i >= 0; i--) 73 | { 74 | ISubscription subscription = this.subscriptions[i]; 75 | if (subscription.TopicFilter.Equals(topicFilter, StringComparison.Ordinal)) 76 | { 77 | return i; 78 | } 79 | } 80 | return -1; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Providers.CloudStorage/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Resources; 6 | using System.Runtime.InteropServices; 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | 12 | [assembly: AssemblyTitle("Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage")] 13 | [assembly: NeutralResourcesLanguage("en-US")] 14 | [assembly: AssemblyMetadata("Serviceable", "True")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | 20 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /src/ProtocolGateway.Providers.CloudStorage/ProtocolGateway.Providers.CloudStorage.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard1.4;net451 5 | Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 6 | Microsoft Azure IoT protocol gateway framework - Azure Storage persistence providers 7 | This library contains the Azure Storage-based persistence components of Azure IoT protocol gateway that enables protocol translation for Azure IoT Hub. 8 | Library 9 | 1.6.1 10 | Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 11 | Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 12 | 2.0.1.0 13 | 2.0.1 14 | en-US 15 | Microsoft 16 | Microsoft Azure IoT protocol gateway 17 | © Microsoft Corporation. All rights reserved. 18 | Microsoft 19 | http://go.microsoft.com/fwlink/?LinkID=288890 20 | https://github.com/Azure/azure-iot-protocol-gateway/blob/master/LICENSE.txt 21 | https://github.com/Azure/azure-iot-protocol-gateway/ 22 | true 23 | Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/ProtocolGateway.Providers.CloudStorage/Subscription.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 5 | { 6 | using System; 7 | using System.Diagnostics.Contracts; 8 | using DotNetty.Codecs.Mqtt.Packets; 9 | using Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence; 10 | using Newtonsoft.Json; 11 | 12 | public class Subscription : ISubscription 13 | { 14 | public Subscription(string topicFilter, QualityOfService qualityOfService) 15 | : this(DateTime.UtcNow, topicFilter, qualityOfService) 16 | { 17 | } 18 | 19 | Subscription(DateTime creationTime, string topicFilter, QualityOfService qualityOfService) 20 | { 21 | this.CreationTime = creationTime; 22 | this.TopicFilter = topicFilter; 23 | this.QualityOfService = qualityOfService; 24 | } 25 | 26 | internal Subscription() 27 | {} 28 | 29 | 30 | [JsonProperty] 31 | public DateTime CreationTime { get; private set; } 32 | 33 | [JsonProperty] 34 | public string TopicFilter { get; private set; } 35 | 36 | [JsonProperty] 37 | public QualityOfService QualityOfService { get; private set; } 38 | 39 | [Pure] 40 | public ISubscription CreateUpdated(QualityOfService qos) => new Subscription(this.CreationTime, this.TopicFilter, qos); 41 | } 42 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Providers.CloudStorage/TableMessageDeliveryState.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Providers.CloudStorage 5 | { 6 | using System; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Mqtt.Persistence; 8 | using Microsoft.WindowsAzure.Storage.Table; 9 | 10 | class TableMessageDeliveryState : TableEntity, IQos2MessageDeliveryState 11 | { 12 | public TableMessageDeliveryState() 13 | { 14 | } 15 | 16 | public TableMessageDeliveryState(ulong sequenceNumber) 17 | { 18 | this.MessageNumber = unchecked ((long)sequenceNumber); 19 | this.LastModified = DateTime.UtcNow; 20 | } 21 | 22 | public DateTime LastModified 23 | { 24 | get { return this.Timestamp.UtcDateTime; } 25 | set { this.Timestamp = value; } 26 | } 27 | 28 | public long MessageNumber { get; set; } 29 | 30 | ulong IQos2MessageDeliveryState.SequenceNumber => unchecked((ulong)this.MessageNumber); 31 | } 32 | } -------------------------------------------------------------------------------- /src/ProtocolGateway.Providers.CloudStorage/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/SharedAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | 6 | [assembly: AssemblyCompany("Microsoft")] 7 | [assembly: AssemblyCopyright("Copyright © Microsoft 2015")] 8 | [assembly: AssemblyVersion("1.0.0.0")] 9 | [assembly: AssemblyFileVersion("1.0.0.0")] 10 | [assembly: AssemblyProduct("Microsoft Azure IoT protocol gateway")] -------------------------------------------------------------------------------- /test/ProtocolGateway.Client.NetStandard/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Resources; 6 | 7 | [assembly: NeutralResourcesLanguage("en-US")] 8 | [assembly: AssemblyMetadata("Serviceable", "True")] -------------------------------------------------------------------------------- /test/ProtocolGateway.Client.NetStandard/ProtocolGateway.Client.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | exe 6 | netcoreapp1.1 7 | 8 | exe 9 | 10 | ProtocolGateway.Client 11 | ProtocolGateway.Client 12 | 1.0.0.0 13 | Microsoft 14 | Copyright © Microsoft 2015 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/ConsoleLoggingHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System; 7 | using DotNetty.Transport.Channels; 8 | 9 | public class ConsoleLoggingHandler : ChannelHandlerAdapter 10 | { 11 | ConsoleLoggingHandler() 12 | { 13 | } 14 | 15 | public static ConsoleLoggingHandler Instance { get; } = new ConsoleLoggingHandler(); 16 | 17 | public override bool IsSharable => true; 18 | 19 | public override void UserEventTriggered(IChannelHandlerContext context, object evt) 20 | { 21 | Console.WriteLine($"User Event: {evt}"); 22 | base.UserEventTriggered(context, evt); 23 | } 24 | 25 | public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) 26 | { 27 | Console.WriteLine($"Exception: {exception}"); 28 | base.ExceptionCaught(context, exception); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | static class EnumerableExtensions 10 | { 11 | public static IEnumerable> InSetsOf(this IEnumerable source, int maxSize) 12 | { 13 | var result = new List(maxSize); 14 | foreach (T item in source) 15 | { 16 | result.Add(item); 17 | if (result.Count == maxSize) 18 | { 19 | yield return result; 20 | result = new List(maxSize); 21 | } 22 | } 23 | if (result.Any()) 24 | { 25 | yield return result; 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/IdProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System.Threading; 7 | 8 | class IdProvider 9 | { 10 | readonly string idPattern; 11 | int lastId; 12 | 13 | public IdProvider(int from, string idPattern) 14 | { 15 | this.idPattern = idPattern; 16 | this.lastId = from - 1; 17 | } 18 | 19 | public string Get() 20 | { 21 | return string.Format(this.idPattern, Interlocked.Increment(ref this.lastId)); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/OccasionalTelemetryRunner.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System; 7 | using System.Net; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using DotNetty.Codecs.Mqtt.Packets; 11 | using DotNetty.Transport.Channels; 12 | 13 | class OccasionalTelemetryRunner : DeviceRunner 14 | { 15 | public OccasionalTelemetryRunner(IEventLoopGroup eventLoopGroup, string deviceKey, string iotHubConnectionString, IPEndPoint endpoint, string tlsHostName) 16 | : base(eventLoopGroup, deviceKey, iotHubConnectionString, endpoint, tlsHostName) 17 | { 18 | } 19 | 20 | protected override string Name => "occasional"; 21 | 22 | protected override async Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId, 23 | CancellationToken cancellationToken) 24 | { 25 | await GetSubscribeSteps(channel, readHandler, clientId); 26 | 27 | await GetPublishSteps(channel, readHandler, clientId, QualityOfService.AtLeastOnce, "devices/{0}/messages/events", 10, 138, 353); 28 | } 29 | 30 | public override async Task OnClosedAsync(string deviceId, Exception exception, bool onStart) 31 | { 32 | if (exception != null) 33 | { 34 | return await base.OnClosedAsync(deviceId, exception, onStart); 35 | } 36 | 37 | await Task.Delay(TimeSpan.FromMinutes(10) + TimeSpan.FromSeconds(Random.Next(-5, 6))); // 10 min +/- 5 sec 38 | return true; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/Options.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using CommandLine; 7 | 8 | class Options 9 | { 10 | [OptionArray('r', "runners", HelpText = "runners configuration in a form of threes: name start-frequency count. Known scenarios are \"stable\", \"occasional\"")] 11 | public string[] Runners { get; set; } 12 | 13 | //[Option('m', "multiply", DefaultValue = 1, HelpText = "multiplication factor per scenario numbers.")] 14 | //public int Multiply { get; set; } 15 | 16 | //[Option('l', "latency", DefaultValue = 40, HelpText = "latency per connection, msec.")] 17 | //public int Latency { get; set; } 18 | 19 | [Option('a', "address", DefaultValue = "127.0.0.1", HelpText = "address to connect to.")] 20 | public string Address { get; set; } 21 | 22 | [Option('p', "port", DefaultValue = 8883, HelpText = "port to connect to.")] 23 | public int Port { get; set; } 24 | 25 | [Option('c', "connection", HelpText = "IoT Hub connection string (without DeviceId).")] 26 | public string IotHubConnectionString { get; set; } 27 | 28 | [Option('h', "hostname", HelpText = "Protocol Gateway host name.")] 29 | public string HostName { get; set; } 30 | 31 | [Option("createdevices", DefaultValue = 0, HelpText = "specifies number of test devices to create.")] 32 | public int CreateDeviceCount { get; set; } 33 | 34 | [Option('s', "devicesfrom", DefaultValue = 1, HelpText = "specifies initial counter value to use for test devices creation and initialization.")] 35 | public int DeviceStartingFrom { get; set; } 36 | 37 | [Option("devicenamepattern", DefaultValue = "testdevice_{0}", HelpText = "specifies name pattern to use for newly created devices. Use \"{0}\" as a placeholder for running counter.")] 38 | public string DeviceNamePattern { get; set; } 39 | 40 | [Option("devicekey", HelpText = "specifies primary key value to use for newly created devices.")] 41 | public string DeviceKey { get; set; } 42 | 43 | [Option("devicekey2", HelpText = "specifies secondary key value to use for newly created devices.")] 44 | public string DeviceKey2 { get; set; } 45 | } 46 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Gateway.Tests.Load")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Gateway.Tests.Load")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("be074eb4-c7ab-42d4-8841-29117cc44983")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/RunnerConfiguration.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | public class RunnerConfiguration 11 | { 12 | public RunnerConfiguration(string name, Func> startFunc, 13 | Func> closedFunc, int count, TimeSpan rampUpPeriod) 14 | { 15 | this.StartFunc = startFunc; 16 | this.ClosedFunc = closedFunc; 17 | this.Count = count; 18 | this.RampUpPeriod = rampUpPeriod; 19 | this.Name = name; 20 | } 21 | 22 | public string Name { get; private set; } 23 | 24 | public int Count { get; private set; } 25 | 26 | public TimeSpan RampUpPeriod { get; private set; } 27 | 28 | /// 29 | /// in: id, out: future for start completion wrapping future for subsequent closure 30 | /// 31 | public Func> StartFunc { get; private set; } 32 | 33 | /// 34 | /// in: Exception on closure (if any), out: future task for decision whether to restart the runner; future can be used 35 | /// to delay execution 36 | /// 37 | public Func> ClosedFunc { get; private set; } 38 | } 39 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/StableTelemetryRunner.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System; 7 | using System.Net; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using DotNetty.Codecs.Mqtt.Packets; 11 | using DotNetty.Transport.Channels; 12 | 13 | class StableTelemetryRunner : DeviceRunner 14 | { 15 | public StableTelemetryRunner(IEventLoopGroup eventLoopGroup, string deviceKey, string iotHubConnectionString, IPEndPoint endpoint, string tlsHostName) 16 | : base(eventLoopGroup, deviceKey, iotHubConnectionString, endpoint, tlsHostName) 17 | { 18 | } 19 | 20 | protected override string Name => "stable"; 21 | 22 | protected override async Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId, 23 | CancellationToken cancellationToken) 24 | { 25 | await GetSubscribeSteps(channel, readHandler, clientId); 26 | 27 | while (!cancellationToken.IsCancellationRequested) 28 | { 29 | await GetPublishSteps(channel, readHandler, clientId, QualityOfService.AtLeastOnce, "devices/{0}/messages/events", 1, 138, 353); 30 | 31 | await channel.EventLoop.ScheduleAsync(() => { }, TimeSpan.FromMinutes(1), cancellationToken); 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests.Load/TaskExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Load 5 | { 6 | using System; 7 | using System.Threading.Tasks; 8 | 9 | static class TaskExtensions 10 | { 11 | public static void LogOnFaulure(this Task task) 12 | { 13 | task.ContinueWith( 14 | t => 15 | { 16 | // todo: log 17 | Console.WriteLine(t.Exception); 18 | }, 19 | TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/ChannelExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests 5 | { 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | using DotNetty.Transport.Channels; 9 | 10 | public static class ChannelExtensions 11 | { 12 | public static Task WriteAndFlushManyAsync(this IChannel channel, params object[] messages) 13 | { 14 | var list = new List(); 15 | foreach (object m in messages) 16 | { 17 | list.Add(channel.WriteAsync(m)); 18 | } 19 | IEnumerable tasks = list.ToArray(); 20 | channel.Flush(); 21 | return Task.WhenAll(tasks); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/DiagnosticsTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests 5 | { 6 | using global::ProtocolGateway.Host.Common; 7 | using Microsoft.Azure.Devices.ProtocolGateway.Instrumentation; 8 | using Microsoft.Practices.EnterpriseLibrary.SemanticLogging.Utility; 9 | using Xunit; 10 | 11 | public class DiagnosticsTests 12 | { 13 | [Fact] 14 | public void VerifyEventSources() 15 | { 16 | EventSourceAnalyzer.InspectAll(CommonEventSource.Log); 17 | EventSourceAnalyzer.InspectAll(BootstrapperEventSource.Log); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/Extensions/ByteBufferExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Extensions 2 | { 3 | using DotNetty.Buffers; 4 | using DotNetty.Common.Utilities; 5 | using System; 6 | 7 | public static class ByteBufferExtensions 8 | { 9 | public static byte[] ToArray(this IByteBuffer buffer) 10 | { 11 | if (!buffer.IsReadable()) 12 | { 13 | return ArrayExtensions.ZeroBytes; 14 | } 15 | var segment = buffer.GetIoBuffer(); 16 | var result = new byte[segment.Count]; 17 | Array.Copy(segment.Array, segment.Offset, result, 0, segment.Count); 18 | return result; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/Extensions/TaskExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests.Extensions 5 | { 6 | using System; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | public static class TaskExtensions 11 | { 12 | public static Task WithTimeout(this Task task, TimeSpan timeout) 13 | { 14 | if (task.IsCompleted || (timeout == Timeout.InfiniteTimeSpan)) 15 | { 16 | return task; 17 | } 18 | 19 | return WithTimeoutInternal(task, timeout); 20 | } 21 | 22 | static async Task WithTimeoutInternal(Task task, TimeSpan timeout) 23 | { 24 | using (var cts = new CancellationTokenSource()) 25 | { 26 | if (task == await Task.WhenAny(task, Task.Delay(timeout, cts.Token))) 27 | { 28 | cts.Cancel(); 29 | await task; 30 | return; 31 | } 32 | } 33 | 34 | throw new TimeoutException(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/MqttTopicMatchingTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using Microsoft.Azure.Devices.ProtocolGateway.Mqtt; 9 | using Xunit; 10 | 11 | public class MqttTopicMatchingTests 12 | { 13 | [Theory] 14 | [InlineData("abc/def", "abc/def", true)] 15 | [InlineData("abc/def", "+/+", true)] 16 | [InlineData("abc/def", "abc/def/#", true)] 17 | [InlineData("abc/def", "abc/defg/#", false)] 18 | [InlineData("abc/defg", "abc/def", false)] 19 | [InlineData("sports/tennis/player1", "sports/tennis/player1/#", true)] 20 | [InlineData("sports/tennis/player1/ranking", "sports/tennis/player1/#", true)] 21 | [InlineData("sports/tennis/player1/score/wimbledon", "sports/tennis/player1/#", true)] 22 | [InlineData("sports/tennis/player1", "sports/tennis/#", true)] 23 | [InlineData("sports", "sports/#", true)] 24 | [InlineData("sport/tennis/player1", "sport/tennis/+", true)] 25 | [InlineData("sport/tennis/", "sport/tennis/+", true)] 26 | [InlineData("sport/tennis", "sport/tennis/+", false)] 27 | [InlineData("sport/tennis/player1/ranking", "sport/tennis/+", false)] 28 | [InlineData("/a/bbb/c", "/a/+/c", true)] 29 | [InlineData("///", "+/+/+/", true)] 30 | [InlineData("/", "+", false)] 31 | [InlineData("/a", "+/a", true)] 32 | [InlineData("abc/a", "+/a", true)] 33 | [InlineData("a/a", "+/a", true)] 34 | [InlineData("/a/bc/c", "/a/+/c", true)] 35 | [InlineData("a", "#", true)] 36 | [InlineData("/", "#", true)] 37 | [InlineData("abc/def", "#", true)] 38 | public void MqttTopicMatchTest(string topicName, string topicFilter, bool expectedResult) 39 | { 40 | bool result = Util.CheckTopicFilterMatch(topicName, topicFilter); 41 | Assert.Equal(expectedResult, result); 42 | } 43 | 44 | [Fact] 45 | public void Experiment() 46 | { 47 | var template = new UriTemplate("devices/{deviceId}/messages/outbound/{*subTopic}"); 48 | var baseUri = new Uri("http://whatever"); 49 | Uri bound = template.BindByName(baseUri, new Dictionary 50 | { 51 | { "deviceId", "VINno" }, 52 | { "SubTopic", "toptop/toptoptop" }, 53 | }); 54 | var t2 = new UriTemplate("devices/{deviceId}/messages/log/{level=info}/{subject=n%2Fa}", true); 55 | UriTemplateMatch match = t2.Match(baseUri, new Uri("http://whatever/devices/VINno/messages/log", UriKind.Absolute)); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Resources; 6 | 7 | [assembly: NeutralResourcesLanguage("en-US")] 8 | [assembly: AssemblyMetadata("Serviceable", "True")] -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/ReadListeningHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests 5 | { 6 | using System; 7 | using System.Collections.Concurrent; 8 | using System.Collections.Generic; 9 | using System.Threading.Tasks; 10 | using DotNetty.Transport.Channels; 11 | 12 | public sealed class ReadListeningHandler : ChannelHandlerAdapter 13 | { 14 | readonly Queue receivedQueue = new Queue(); 15 | readonly ConcurrentQueue> readPromises; 16 | Exception registeredException; 17 | readonly TimeSpan defaultReadTimeout; 18 | 19 | public ReadListeningHandler() 20 | : this(TimeSpan.Zero) 21 | { 22 | } 23 | 24 | public ReadListeningHandler(TimeSpan defaultReadTimeout) 25 | { 26 | this.defaultReadTimeout = defaultReadTimeout; 27 | this.readPromises = new ConcurrentQueue>(); 28 | } 29 | 30 | public override void ChannelRead(IChannelHandlerContext context, object message) 31 | { 32 | TaskCompletionSource promise; 33 | if (this.readPromises.TryDequeue(out promise)) 34 | { 35 | promise.TrySetResult(message); 36 | } 37 | else 38 | { 39 | this.receivedQueue.Enqueue(message); 40 | } 41 | } 42 | 43 | public override void ChannelInactive(IChannelHandlerContext context) 44 | { 45 | this.SetException(new InvalidOperationException("Channel is closed.")); 46 | base.ChannelInactive(context); 47 | } 48 | 49 | public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) => this.SetException(exception); 50 | 51 | void SetException(Exception exception) 52 | { 53 | this.registeredException = exception; 54 | TaskCompletionSource promise; 55 | while (this.readPromises.TryDequeue(out promise)) 56 | { 57 | promise.TrySetException(exception); 58 | } 59 | } 60 | 61 | public async Task ReceiveAsync(TimeSpan timeout = default(TimeSpan)) 62 | { 63 | if (this.registeredException != null) 64 | { 65 | throw this.registeredException; 66 | } 67 | 68 | if (this.receivedQueue.Count > 0) 69 | { 70 | return this.receivedQueue.Dequeue(); 71 | } 72 | 73 | var promise = new TaskCompletionSource(); 74 | this.readPromises.Enqueue(promise); 75 | 76 | timeout = timeout <= TimeSpan.Zero ? this.defaultReadTimeout : timeout; 77 | if (timeout > TimeSpan.Zero) 78 | { 79 | Task task = await Task.WhenAny(promise.Task, Task.Delay(timeout)); 80 | if (task != promise.Task) 81 | { 82 | throw new TimeoutException("ReceiveAsync timed out"); 83 | } 84 | 85 | return promise.Task.Result; 86 | } 87 | 88 | return await promise.Task; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/XUnitLoggingHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests 5 | { 6 | using System; 7 | using DotNetty.Transport.Channels; 8 | using Xunit.Abstractions; 9 | 10 | public class XUnitLoggingHandler : ChannelHandlerAdapter 11 | { 12 | readonly ITestOutputHelper output; 13 | 14 | public XUnitLoggingHandler(ITestOutputHelper output) 15 | { 16 | this.output = output; 17 | } 18 | 19 | public override void UserEventTriggered(IChannelHandlerContext context, object evt) 20 | { 21 | this.output.WriteLine($"User Event: {evt}"); 22 | base.UserEventTriggered(context, evt); 23 | } 24 | 25 | public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) 26 | { 27 | this.output.WriteLine($"Exception: {exception}"); 28 | base.ExceptionCaught(context, exception); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/XUnitOutputSink.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Azure.Devices.ProtocolGateway.Tests 5 | { 6 | using System; 7 | using Microsoft.Practices.EnterpriseLibrary.SemanticLogging; 8 | using Microsoft.Practices.EnterpriseLibrary.SemanticLogging.Formatters; 9 | using Microsoft.Practices.EnterpriseLibrary.SemanticLogging.Utility; 10 | using Xunit.Abstractions; 11 | 12 | public class XUnitOutputSink : IObserver 13 | { 14 | static readonly object LockObject = new object(); 15 | readonly ITestOutputHelper output; 16 | readonly IEventTextFormatter formatter; 17 | 18 | public XUnitOutputSink(ITestOutputHelper output, IEventTextFormatter formatter) 19 | { 20 | this.output = output; 21 | this.formatter = formatter; 22 | } 23 | 24 | public void OnCompleted() 25 | { 26 | } 27 | 28 | public void OnError(Exception error) 29 | { 30 | } 31 | 32 | public void OnNext(EventEntry value) 33 | { 34 | string formattedValue = value.TryFormatAsString(this.formatter); 35 | if (formattedValue == null) 36 | { 37 | return; 38 | } 39 | this.OnNext(formattedValue); 40 | } 41 | 42 | void OnNext(string entry) 43 | { 44 | lock (LockObject) 45 | { 46 | try 47 | { 48 | this.output.WriteLine(entry); 49 | } 50 | catch (Exception ex) 51 | { 52 | SemanticLoggingEventSource.Log.CustomSinkUnhandledFault(ex.ToString()); 53 | } 54 | } 55 | } 56 | } 57 | 58 | public static class XUnitOutputLog 59 | { 60 | public static SinkSubscription LogToTestOutput(this IObservable eventStream, ITestOutputHelper output, IEventTextFormatter formatter = null) 61 | { 62 | formatter = formatter ?? new EventTextFormatter(); 63 | var sink = new XUnitOutputSink(output, formatter); 64 | return new SinkSubscription(eventStream.Subscribe(sink), sink); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/appSettings.config.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/mqttTopicConversion.config.user: -------------------------------------------------------------------------------- 1 | 2 | devices/{deviceId}/messages/events 3 | devices/{deviceId}/messages/devicebound 4 | -------------------------------------------------------------------------------- /test/ProtocolGateway.Tests/tlscert.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-iot-protocol-gateway/4f6d32d1116a2cbc50fd608c8a5b44f5a1037971/test/ProtocolGateway.Tests/tlscert.pfx --------------------------------------------------------------------------------