Example #1
0
 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);
     }
 }
Example #2
0
        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;
                }
                }
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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;
                }
                }
            }
        }
Example #8
0
        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));
                }
            }
        }
Example #11
0
        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)}");
                }
            }
        }