public async Task MqttWebSocketClientAndServerScenario()
        {
            var websocket = new ClientWebSocket();

            websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt);
            Uri uri = new Uri("ws://" + IotHubName + ":" + Port + WebSocketConstants.UriSuffix);
            await websocket.ConnectAsync(uri, CancellationToken.None);

            var clientReadListener = new ReadListeningHandler();
            var clientChannel      = new ClientWebSocketChannel(null, websocket);

            clientChannel
            .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
            .Option(ChannelOption.AutoRead, true)
            .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
            .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default);

            clientChannel.Pipeline.AddLast(
                MqttEncoder.Instance,
                new MqttDecoder(false, 256 * 1024),
                clientReadListener);
            var clientWorkerGroup = new MultithreadEventLoopGroup();
            await clientWorkerGroup.GetNext().RegisterAsync(clientChannel);

            await Task.WhenAll(RunMqttClientScenarioAsync(clientChannel, clientReadListener), RunMqttServerScenarioAsync(serverWebSocketChannel, serverListener));

            done = true;
        }
        private async Task <RegistrationOperationStatus> ProvisionOverWssCommonAsync(
            ProvisioningTransportRegisterMessage message,
            X509Certificate2 clientCertificate,
            CancellationToken cancellationToken)
        {
            var tcs = new TaskCompletionSource <RegistrationOperationStatus>();

            var uriBuilder   = new UriBuilder(WsScheme, message.GlobalDeviceEndpoint, Port);
            Uri websocketUri = uriBuilder.Uri;

            using var websocket = new ClientWebSocket();
            websocket.Options.AddSubProtocol(WsMqttSubprotocol);
            if (clientCertificate != null)
            {
                websocket.Options.ClientCertificates.Add(clientCertificate);
            }

            //Check if we're configured to use a proxy server
            try
            {
                if (Proxy != DefaultWebProxySettings.Instance)
                {
                    // Configure proxy server
                    websocket.Options.Proxy = Proxy;
                    if (Logging.IsEnabled)
                    {
                        Logging.Info(this, $"{nameof(ProvisionOverWssUsingX509CertificateAsync)} Setting ClientWebSocket.Options.Proxy: {Proxy}");
                    }
                }
            }
            catch (PlatformNotSupportedException)
            {
                // .NET Core 2.0 doesn't support WebProxy configuration - ignore this setting.
                if (Logging.IsEnabled)
                {
                    Logging.Error(this, $"{nameof(ProvisionOverWssUsingX509CertificateAsync)} PlatformNotSupportedException thrown as .NET Core 2.0 doesn't support proxy");
                }
            }

            await websocket.ConnectAsync(websocketUri, cancellationToken).ConfigureAwait(false);

            var clientChannel = new ClientWebSocketChannel(null, websocket);

            clientChannel
            .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
            .Option(ChannelOption.AutoRead, true)
            .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
            .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default)
            .Pipeline.AddLast(
                new ReadTimeoutHandler(ReadTimeoutSeconds),
                MqttEncoder.Instance,
                new MqttDecoder(false, MaxMessageSize),
                new LoggingHandler(LogLevel.DEBUG),
                new ProvisioningChannelHandlerAdapter(message, tcs, cancellationToken));

            await s_eventLoopGroup.RegisterAsync(clientChannel).ConfigureAwait(false);

            return(await tcs.Task.ConfigureAwait(false));
        }
        private async Task <RegistrationOperationStatus> ProvisionOverWssUsingX509CertificateAsync(
            ProvisioningTransportRegisterMessage message,
            CancellationToken cancellationToken)
        {
            Debug.Assert(message.Security is SecurityProviderX509);
            cancellationToken.ThrowIfCancellationRequested();

            X509Certificate2 clientCertificate =
                ((SecurityProviderX509)message.Security).GetAuthenticationCertificate();

            var tcs = new TaskCompletionSource <RegistrationOperationStatus>();

            UriBuilder uriBuilder   = new UriBuilder(WsScheme, message.GlobalDeviceEndpoint, Port);
            Uri        websocketUri = uriBuilder.Uri;

            // TODO properly dispose of the ws.
            var websocket = new ClientWebSocket();

            websocket.Options.AddSubProtocol(WsMqttSubprotocol);
            websocket.Options.ClientCertificates.Add(clientCertificate);

            await websocket.ConnectAsync(websocketUri, cancellationToken).ConfigureAwait(false);

            // TODO: use ClientWebSocketChannel.
            var clientChannel = new ClientWebSocketChannel(null, websocket);

            clientChannel
            .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
            .Option(ChannelOption.AutoRead, true)
            .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
            .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default)
            .Pipeline.AddLast(
                new ReadTimeoutHandler(ReadTimeoutSeconds),
                MqttEncoder.Instance,
                new MqttDecoder(false, MaxMessageSize),
                new ProvisioningChannelHandlerAdapter(message, tcs, cancellationToken));

            await s_eventLoopGroup.RegisterAsync(clientChannel).ConfigureAwait(false);

            return(await tcs.Task.ConfigureAwait(false));
        }
        public async Task ClientWebSocketChannelReadAfterCloseTest()
        {
            var websocket = new ClientWebSocket();

            websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt);
            var uri = new Uri("ws://" + IotHubName + ":" + Port + WebSocketConstants.UriSuffix);
            await websocket.ConnectAsync(uri, CancellationToken.None);

            var clientReadListener = new ReadListeningHandler();
            var clientChannel      = new ClientWebSocketChannel(null, websocket);

            clientChannel
            .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
            .Option(ChannelOption.AutoRead, true)
            .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
            .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default);

            clientChannel.Pipeline.AddLast(
                clientReadListener);
            var threadLoop = new SingleThreadEventLoop("MQTTExecutionThread", TimeSpan.FromSeconds(1));
            await threadLoop.RegisterAsync(clientChannel);

            await clientChannel.CloseAsync();

            // Test Read API
            try
            {
                await clientReadListener.ReceiveAsync(DefaultTimeout);

                Assert.Fail("Should have thrown InvalidOperationException");
            }
            catch (InvalidOperationException e)
            {
                Assert.IsTrue(e.Message.Contains("Channel is closed"));
            }

            done = true;
        }
        public async Task ClientWebSocketChannelReadAfterCloseTest()
        {
            var websocket = new ClientWebSocket();
            websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt);
            var uri = new Uri("ws://" + IotHubName + ":" + Port + WebSocketConstants.UriSuffix);
            await websocket.ConnectAsync(uri, CancellationToken.None);

            var clientReadListener = new ReadListeningHandler();
            var clientChannel = new ClientWebSocketChannel(null, websocket);
            clientChannel
                .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
                .Option(ChannelOption.AutoRead, true)
                .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
                .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default);

            clientChannel.Pipeline.AddLast(
                clientReadListener);
            var threadLoop = new SingleThreadEventLoop("MQTTExecutionThread", TimeSpan.FromSeconds(1));
            await threadLoop.RegisterAsync(clientChannel);
            await clientChannel.CloseAsync();
                
            // Test Read API
            try
            {
                await clientReadListener.ReceiveAsync(DefaultTimeout);
                Assert.Fail("Should have thrown InvalidOperationException");
            }
            catch (InvalidOperationException e)
            {
                Assert.IsTrue(e.Message.Contains("Channel is closed"));
            }

            done = true;
        }
        public async Task MqttWebSocketClientAndServerScenario()
        {
            var websocket = new ClientWebSocket();
            websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt);
            Uri uri = new Uri("ws://" + IotHubName + ":" + Port + WebSocketConstants.UriSuffix);
            await websocket.ConnectAsync(uri, CancellationToken.None);

            var clientReadListener = new ReadListeningHandler();
            var clientChannel = new ClientWebSocketChannel(null, websocket);
            clientChannel
                .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
                .Option(ChannelOption.AutoRead, true)
                .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
                .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default);
            
            clientChannel.Pipeline.AddLast(
                MqttEncoder.Instance,
                new MqttDecoder(false, 256 * 1024),
                clientReadListener);
            var clientWorkerGroup = new MultithreadEventLoopGroup();
            await clientWorkerGroup.GetNext().RegisterAsync(clientChannel);

            await Task.WhenAll(RunMqttClientScenarioAsync(clientChannel, clientReadListener), RunMqttServerScenarioAsync(serverWebSocketChannel, serverListener));
            done = true;
        }
        Func<IPAddress, int, Task<IChannel>> CreateWebSocketChannelFactory(IotHubConnectionString iotHubConnectionString, MqttTransportSettings settings)
        {
            return async (address, port) =>
            {
                IEventLoopGroup eventLoopGroup = EventLoopGroupPool.TakeOrAdd(this.eventLoopGroupKey);

                var websocketUri = new Uri(WebSocketConstants.Scheme + iotHubConnectionString.HostName + ":" + WebSocketConstants.SecurePort + WebSocketConstants.UriSuffix);
                var websocket = new ClientWebSocket();
                websocket.Options.AddSubProtocol(WebSocketConstants.SubProtocols.Mqtt);

                // Check if we're configured to use a proxy server
                IWebProxy webProxy = WebRequest.DefaultWebProxy;
                Uri proxyAddress = webProxy?.GetProxy(websocketUri);
                if (!websocketUri.Equals(proxyAddress))
                {
                    // Configure proxy server
                    websocket.Options.Proxy = webProxy;
                }

                if (settings.ClientCertificate != null)
                {
                    websocket.Options.ClientCertificates.Add(settings.ClientCertificate);
                }
                else
                {
                    websocket.Options.UseDefaultCredentials = true;
                }

                using (var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(1)))
                {
                    await websocket.ConnectAsync(websocketUri, cancellationTokenSource.Token);
                }

                var clientChannel = new ClientWebSocketChannel(null, websocket);
                clientChannel
                    .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
                    .Option(ChannelOption.AutoRead, false)
                    .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
                    .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default)
                    .Pipeline.AddLast(
                        MqttEncoder.Instance,
                        new MqttDecoder(false, MaxMessageSize),
                        this.mqttIotHubAdapterFactory.Create(this.OnConnected, this.OnMessageReceived, this.OnError, iotHubConnectionString, settings));
                await eventLoopGroup.GetNext().RegisterAsync(clientChannel);

                this.ScheduleCleanup(() =>
                {
                    EventLoopGroupPool.Release(this.eventLoopGroupKey);
                    return TaskConstants.Completed;
                });

                return clientChannel;
            };
        }