public void InstallCaCertificates(IEnumerable <X509Certificate2> certs, ITransportSettings transportSettings) { if (transportSettings.GetTransportType() == TransportType.Amqp_WebSocket_Only || transportSettings.GetTransportType() == TransportType.Amqp_Tcp_Only) { transportSettings.SetupCertificateValidation(certs.First()); } else { this.InstallTrustedCertificates(certs, StoreName.Root); } }
private void SelectTransport() { if (!_transportSelectionComplete) { // Try next protocol if we're still searching. ITransportSettings[] transportSettingsArray = Context.Get <ITransportSettings[]>(); Debug.Assert(transportSettingsArray != null); // Keep cycling through all transports until we find one that works. if (_nextTransportIndex >= transportSettingsArray.Length) { _nextTransportIndex = 0; } ITransportSettings transportSettings = transportSettingsArray[_nextTransportIndex]; Debug.Assert(transportSettings != null); if (Logging.IsEnabled) { Logging.Info( this, $"Trying {transportSettings?.GetTransportType()}", $"{nameof(ProtocolRoutingDelegatingHandler)}.{nameof(OpenAsync)}"); } // Configure the transportSettings for this context (Important! Within Context, 'ITransportSettings' != 'ITransportSettings[]'). Context.Set <ITransportSettings>(transportSettings); CreateNewTransportHandler(); _nextTransportIndex++; } }
public void GetTransportSettingsTest(Option <UpstreamProtocol> upstreamProtocol, int connectionPoolSize, Option <IWebProxy> proxy, ITransportSettings[] expectedTransportSettingsList, bool useServerHeartbeat) { const string expectedAuthChain = "e3;e2;e1"; ITransportSettings[] transportSettingsList = CloudConnectionProvider.GetTransportSettings(upstreamProtocol, connectionPoolSize, proxy, useServerHeartbeat, expectedAuthChain); Assert.NotNull(transportSettingsList); Assert.Equal(expectedTransportSettingsList.Length, transportSettingsList.Length); for (int i = 0; i < expectedTransportSettingsList.Length; i++) { ITransportSettings expectedTransportSettings = expectedTransportSettingsList[i]; ITransportSettings transportSettings = transportSettingsList[i]; Assert.Equal(expectedTransportSettings.GetType(), transportSettings.GetType()); Assert.Equal(expectedTransportSettings.GetTransportType(), transportSettings.GetTransportType()); // Check authchain via Reflection string authChain = (string)transportSettings.GetType() .GetProperty("AuthenticationChain", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(transportSettings); Assert.Equal(authChain, expectedAuthChain); switch (expectedTransportSettings) { case AmqpTransportSettings _: { var expected = (AmqpTransportSettings)expectedTransportSettings; var actual = (AmqpTransportSettings)transportSettings; Assert.True(expected.Equals(actual)); // AmqpTransportSettings impls Equals, but doesn't override Object.Equals if (proxy == Option.None <IWebProxy>()) { Assert.Null(actual.Proxy); } else { Assert.True(actual.Proxy is WebProxy); Assert.Equal(((WebProxy)expected.Proxy).Address, ((WebProxy)actual.Proxy).Address); } break; } case MqttTransportSettings _: { var expected = (MqttTransportSettings)expectedTransportSettings; var actual = (MqttTransportSettings)transportSettings; Assert.True(actual.Proxy is WebProxy); Assert.Equal(((WebProxy)expected.Proxy).Address, ((WebProxy)actual.Proxy).Address); break; } } } }
static async Task <Client.ModuleClient> CreateAndOpenDeviceClient( UpstreamProtocol upstreamProtocol, Option <string> connectionString, ConnectionStatusChangesHandler statusChangedHandler, Option <IWebProxy> proxy, Option <string> productInfo) { ITransportSettings settings = GetTransportSettings(upstreamProtocol, proxy); Events.AttemptingConnectionWithTransport(settings.GetTransportType()); Client.ModuleClient deviceClient = await connectionString .Map(cs => Task.FromResult(Client.ModuleClient.CreateFromConnectionString(cs, new[] { settings }))) .GetOrElse(() => Client.ModuleClient.CreateFromEnvironmentAsync(new[] { settings })); productInfo.ForEach(p => deviceClient.ProductInfo = p); await OpenAsync(statusChangedHandler, deviceClient); Events.ConnectedWithTransport(settings.GetTransportType()); return(deviceClient); }
async Task <ISdkModuleClient> CreateAndOpenSdkModuleClient(UpstreamProtocol upstreamProtocol, ConnectionStatusChangesHandler statusChangedHandler) { ITransportSettings settings = GetTransportSettings(upstreamProtocol, this.proxy); Events.AttemptingConnectionWithTransport(settings.GetTransportType()); ISdkModuleClient moduleClient = await this.connectionString .Map(cs => Task.FromResult(this.sdkModuleClientProvider.GetSdkModuleClient(cs, settings))) .GetOrElse(this.sdkModuleClientProvider.GetSdkModuleClient(settings)); moduleClient.SetProductInfo(this.productInfo); // note: it's important to set the status-changed handler and // timeout value *before* we open a connection to the hub moduleClient.SetOperationTimeoutInMilliseconds(ModuleClientTimeoutMilliseconds); moduleClient.SetConnectionStatusChangesHandler(statusChangedHandler); await moduleClient.OpenAsync(); Events.ConnectedWithTransport(settings.GetTransportType()); return(moduleClient); }
public IDelegatingHandler Create(PipelineContext context) { // ProtocolRoutingDelegatingHandler configures the ITransportSettings configuration // which is different from ITransportSettings[] element. ITransportSettings transportSetting = context.TransportSettings; IotHubConnectionString connectionString = context.IotHubConnectionString; InternalClient.OnMethodCalledDelegate onMethodCallback = context.MethodCallback; Action <TwinCollection> onDesiredStatePatchReceived = context.DesiredPropertyUpdateCallback; InternalClient.OnModuleEventMessageReceivedDelegate onModuleEventReceivedCallback = context.ModuleEventCallback; InternalClient.OnDeviceMessageReceivedDelegate onDeviceMessageReceivedCallback = context.DeviceEventCallback; switch (transportSetting.GetTransportType()) { case TransportType.Amqp_WebSocket_Only: case TransportType.Amqp_Tcp_Only: return(new AmqpTransportHandler( context, connectionString, transportSetting as AmqpTransportSettings, new Func <MethodRequestInternal, Task>(onMethodCallback), onDesiredStatePatchReceived, new Func <string, Message, Task>(onModuleEventReceivedCallback), new Func <Message, Task>(onDeviceMessageReceivedCallback))); case TransportType.Http1: return(new HttpTransportHandler( context, connectionString, transportSetting as Http1TransportSettings, isClientPrimaryTransportHandler: true)); case TransportType.Mqtt_Tcp_Only: case TransportType.Mqtt_WebSocket_Only: return(new MqttTransportHandler( context, connectionString, transportSetting as MqttTransportSettings, new Func <MethodRequestInternal, Task>(onMethodCallback), onDesiredStatePatchReceived, new Func <string, Message, Task>(onModuleEventReceivedCallback), new Func <Message, Task>(onDeviceMessageReceivedCallback))); default: throw new InvalidOperationException($"Unsupported transport setting {transportSetting}"); } }
public void GetTransportSettingsTest(Option <UpstreamProtocol> upstreamProtocol, int connectionPoolSize, Option <IWebProxy> proxy, ITransportSettings[] expectedTransportSettingsList) { ITransportSettings[] transportSettingsList = CloudConnectionProvider.GetTransportSettings(upstreamProtocol, connectionPoolSize, proxy); Assert.NotNull(transportSettingsList); Assert.Equal(expectedTransportSettingsList.Length, transportSettingsList.Length); for (int i = 0; i < expectedTransportSettingsList.Length; i++) { ITransportSettings expectedTransportSettings = expectedTransportSettingsList[i]; ITransportSettings transportSettings = transportSettingsList[i]; Assert.Equal(expectedTransportSettings.GetType(), transportSettings.GetType()); Assert.Equal(expectedTransportSettings.GetTransportType(), transportSettings.GetTransportType()); switch (expectedTransportSettings) { case AmqpTransportSettings _: { var expected = (AmqpTransportSettings)expectedTransportSettings; var actual = (AmqpTransportSettings)transportSettings; Assert.True(expected.Equals(actual)); // AmqpTransportSettings impls Equals, but doesn't override Object.Equals if (proxy == Option.None <IWebProxy>()) { Assert.Null(actual.Proxy); } else { Assert.True(actual.Proxy is WebProxy); Assert.Equal(((WebProxy)expected.Proxy).Address, ((WebProxy)actual.Proxy).Address); } break; } case MqttTransportSettings _: { var expected = (MqttTransportSettings)expectedTransportSettings; var actual = (MqttTransportSettings)transportSettings; Assert.True(actual.Proxy is WebProxy); Assert.Equal(((WebProxy)expected.Proxy).Address, ((WebProxy)actual.Proxy).Address); break; } } } }
DefaultDelegatingHandler CreateTransportHandler(IotHubConnectionString iotHubConnectionString, ITransportSettings transportSetting) { switch (transportSetting.GetTransportType()) { case TransportType.Amqp_WebSocket_Only: case TransportType.Amqp_Tcp_Only: return(new AmqpTransportHandler(iotHubConnectionString, transportSetting as AmqpTransportSettings)); case TransportType.Http1: return(new HttpTransportHandler(iotHubConnectionString, transportSetting as Http1TransportSettings)); case TransportType.Mqtt: return(new MqttTransportHandler(iotHubConnectionString, transportSetting as MqttTransportSettings)); default: throw new InvalidOperationException("Unsupported Transport Setting {0}".FormatInvariant(transportSetting)); } }
public IDelegatingHandler Create(IPipelineContext context) { // ProtocolRoutingDelegatingHandler configures the ITransportSettings configuration // which is different from ITransportSettings[] element. ITransportSettings transportSetting = context.Get <ITransportSettings>(); IotHubConnectionString connectionString = context.Get <IotHubConnectionString>(); InternalClient.OnMethodCalledDelegate onMethodCallback = context.Get <InternalClient.OnMethodCalledDelegate>(); Action <TwinCollection> onDesiredStatePatchReceived = context.Get <Action <TwinCollection> >(); InternalClient.OnModuleEventMessageReceivedDelegate onModuleEventReceivedCallback = context.Get <InternalClient.OnModuleEventMessageReceivedDelegate>(); InternalClient.OnDeviceMessageReceivedDelegate onDeviceMessageReceivedCallback = context.Get <InternalClient.OnDeviceMessageReceivedDelegate>(); switch (transportSetting.GetTransportType()) { case TransportType.Amqp_WebSocket_Only: case TransportType.Amqp_Tcp_Only: return(new AmqpTransportHandler( context, connectionString, transportSetting as AmqpTransportSettings, new Func <MethodRequestInternal, Task>(onMethodCallback), onDesiredStatePatchReceived, new Func <string, Message, Task>(onModuleEventReceivedCallback), new Func <Message, Task>(onDeviceMessageReceivedCallback))); case TransportType.Http1: return(new HttpTransportHandler(context, connectionString, transportSetting as Http1TransportSettings)); case TransportType.Mqtt_Tcp_Only: case TransportType.Mqtt_WebSocket_Only: return(new MqttTransportHandler( context, connectionString, transportSetting as MqttTransportSettings, new Func <MethodRequestInternal, Task>(onMethodCallback), onDesiredStatePatchReceived, new Func <string, Message, Task>(onModuleEventReceivedCallback), new Func <Message, Task>(onDeviceMessageReceivedCallback))); default: throw new InvalidOperationException("Unsupported Transport Setting {0}".FormatInvariant(transportSetting)); } }
public void GetTransportSettingsTest(Option <UpstreamProtocol> upstreamProtocol, int connectionPoolSize, ITransportSettings[] expectedTransportSettingsList) { ITransportSettings[] transportSettingsList = CloudConnectionProvider.GetTransportSettings(upstreamProtocol, connectionPoolSize); Assert.NotNull(transportSettingsList); Assert.Equal(expectedTransportSettingsList.Length, transportSettingsList.Length); for (int i = 0; i < expectedTransportSettingsList.Length; i++) { ITransportSettings expectedTransportSettings = expectedTransportSettingsList[i]; ITransportSettings transportSettings = transportSettingsList[i]; Assert.Equal(expectedTransportSettings.GetType(), transportSettings.GetType()); Assert.Equal(expectedTransportSettings.GetTransportType(), transportSettings.GetTransportType()); if (expectedTransportSettings is AmqpTransportSettings) { Assert.True(((AmqpTransportSettings)expectedTransportSettings).Equals((AmqpTransportSettings)transportSettings)); } } }
public static void SetupCertificateValidation(this ITransportSettings transportSettings, X509Certificate2 trustedCert) { switch (transportSettings.GetTransportType()) { case TransportType.Amqp_WebSocket_Only: case TransportType.Amqp_Tcp_Only: if (transportSettings is AmqpTransportSettings amqpTransportSettings) { if (amqpTransportSettings.RemoteCertificateValidationCallback == null) { amqpTransportSettings.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => ValidateCertificate(trustedCert, certificate, chain, sslPolicyErrors); } } break; case TransportType.Http1: // InvokeMethodAsync is over HTTP even when transportSettings set a different protocol // So set the callback in HttpClientHandler for InvokeMethodAsync break; case TransportType.Mqtt_WebSocket_Only: case TransportType.Mqtt_Tcp_Only: if (transportSettings is MqttTransportSettings mqttTransportSettings) { if (mqttTransportSettings.RemoteCertificateValidationCallback == null) { mqttTransportSettings.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => ValidateCertificate(trustedCert, certificate, chain, sslPolicyErrors); } } break; default: throw new InvalidEnumArgumentException(); } }
DefaultDelegatingHandler CreateTransportHandler(IotHubConnectionString iotHubConnectionString, ITransportSettings transportSetting) { switch (transportSetting.GetTransportType()) { case TransportType.Amqp_WebSocket_Only: case TransportType.Amqp_Tcp_Only: return new AmqpTransportHandler(iotHubConnectionString, transportSetting as AmqpTransportSettings); case TransportType.Http1: return new HttpTransportHandler(iotHubConnectionString, transportSetting as Http1TransportSettings); #if !WINDOWS_UWP && !NETMF case TransportType.Mqtt: return new MqttTransportHandler(iotHubConnectionString, transportSetting as MqttTransportSettings); #endif default: throw new InvalidOperationException("Unsupported Transport Setting {0}".FormatInvariant(transportSetting)); } }
public override async Task OpenAsync(CancellationToken cancellationToken) { try { if (Logging.IsEnabled) { Logging.Enter(this, cancellationToken, $"{nameof(ProtocolRoutingDelegatingHandler)}.{nameof(OpenAsync)}"); } cancellationToken.ThrowIfCancellationRequested(); await _handlerLock.WaitAsync().ConfigureAwait(false); if (!_transportSelectionComplete) { // Try next protocol if we're still searching. ITransportSettings[] transportSettingsArray = this.Context.Get <ITransportSettings[]>(); Debug.Assert(transportSettingsArray != null); // Keep cycling through all transports until we find one that works. if (_nextTransportIndex >= transportSettingsArray.Length) { _nextTransportIndex = 0; } ITransportSettings transportSettings = transportSettingsArray[_nextTransportIndex]; Debug.Assert(transportSettings != null); if (Logging.IsEnabled) { Logging.Info( this, $"Trying {transportSettings?.GetTransportType()}", $"{nameof(ProtocolRoutingDelegatingHandler)}.{nameof(OpenAsync)}"); } // Configure the transportSettings for this context (Important! Within Context, 'ITransportSettings' != 'ITransportSettings[]'). Context.Set <ITransportSettings>(transportSettings); CreateNewTransportHandler(); _nextTransportIndex++; } try { await base.OpenAsync(cancellationToken).ConfigureAwait(false); _transportSelectionComplete = true; } finally { _handlerLock.Release(); } } finally { if (Logging.IsEnabled) { Logging.Exit(this, cancellationToken, $"{nameof(ProtocolRoutingDelegatingHandler)}.{nameof(OpenAsync)}"); } } }