Esempio n. 1
0
        protected override async Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId,
                                                  CancellationToken cancellationToken)
        {
            await GetSubscribeSteps(channel, readHandler, clientId);

            await GetPublishSteps(channel, readHandler, clientId, QualityOfService.AtLeastOnce, "devices/{0}/messages/events", 10, 138, 353);
        }
        async Task GetCompleteScenarioAsync(IChannel channel, ReadListeningHandler readHandler, string clientId, string password, CancellationToken cancellationToken)
        {
            await channel.WriteAndFlushAsync(new ConnectPacket
            {
                ClientId           = clientId,
                CleanSession       = false,
                HasUsername        = true,
                Username           = clientId,
                HasPassword        = true,
                Password           = password,
                KeepAliveInSeconds = 120
            });

            object message = await readHandler.ReceiveAsync();

            var connackPacket = message as ConnAckPacket;

            if (connackPacket == null)
            {
                throw new InvalidOperationException(string.Format("{1}: Expected CONNACK, received {0}", message, clientId));
            }
            else if (connackPacket.ReturnCode != ConnectReturnCode.Accepted)
            {
                throw new InvalidOperationException(string.Format("{1}: Expected successful CONNACK, received CONNACK with return code of {0}", connackPacket.ReturnCode, clientId));
            }

            await this.GetScenario(channel, readHandler, clientId, cancellationToken);
        }
        protected override async Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId,
            CancellationToken cancellationToken)
        {
            await GetSubscribeSteps(channel, readHandler, clientId);

            await GetPublishSteps(channel, readHandler, clientId, QualityOfService.AtLeastOnce, "devices/{0}/messages/events", 10, 138, 353);
        }
        public async Task <Task> StartAsync(string deviceId, CancellationToken cancellationToken)
        {
            string deviceSas =
                new SharedAccessSignatureBuilder
            {
                Key        = this.deviceKey,
                Target     = $"{this.connectionStringBuilder.HostName}/devices/{deviceId}",
                TimeToLive = TimeSpan.FromDays(3)
            }
            .ToSignature();

            var       taskCompletionSource = new TaskCompletionSource();
            Bootstrap b           = this.bootstrap.Clone();
            var       readHandler = new ReadListeningHandler(CommunicationTimeout);

            b.Handler(new ActionChannelInitializer <ISocketChannel>(
                          ch =>
            {
                ch.Pipeline.AddLast(
                    new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(this.tlsHostName)),
                    MqttEncoder.Instance,
                    new MqttDecoder(false, 256 * 1024),
                    readHandler,
                    ConsoleLoggingHandler.Instance);
            }));

            var channel = await b.ConnectAsync(this.endpoint);

            await this.GetCompleteScenarioAsync(channel, readHandler, deviceId, deviceSas, cancellationToken);

            return(taskCompletionSource.Task);
        }
        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;
        }
        public async Task<Task> StartAsync(string deviceId, CancellationToken cancellationToken)
        {
            string deviceSas =
                new SharedAccessSignatureBuilder
                {
                    Key = this.deviceKey,
                    Target = $"{this.connectionStringBuilder.HostName}/devices/{deviceId}",
                    TimeToLive = TimeSpan.FromDays(3)
                }
                    .ToSignature();

            var taskCompletionSource = new TaskCompletionSource();
            Bootstrap b = this.bootstrap.Clone();
            var readHandler = new ReadListeningHandler(CommunicationTimeout);
            b.Handler(new ActionChannelInitializer<ISocketChannel>(
                ch =>
                {
                    ch.Pipeline.AddLast(
                        new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(this.tlsHostName)),
                        MqttEncoder.Instance,
                        new MqttDecoder(false, 256 * 1024),
                        readHandler,
                        ConsoleLoggingHandler.Instance);
                }));

            var channel = await b.ConnectAsync(this.endpoint);

            await this.GetCompleteScenarioAsync(channel, readHandler, deviceId, deviceSas, cancellationToken);
            
            return taskCompletionSource.Task;
        }
        static async Task RunMqttServerScenarioAsync(IChannel channel, ReadListeningHandler readListener)
        {
            var connectPacket = await readListener.ReceiveAsync(DefaultTimeout) as ConnectPacket;

            Assert.IsNotNull(connectPacket, "Must be a Connect pkt");
            // todo verify

            await channel.WriteAndFlushAsync(new ConnAckPacket
            {
                ReturnCode     = ConnectReturnCode.Accepted,
                SessionPresent = true
            });

            var subscribePacket = await readListener.ReceiveAsync(DefaultTimeout) as SubscribePacket;

            Assert.IsNotNull(subscribePacket);
            // todo verify

            await channel.WriteAndFlushAsync(SubAckPacket.InResponseTo(subscribePacket, QualityOfService.ExactlyOnce));

            var unsubscribePacket = await readListener.ReceiveAsync(DefaultTimeout) as UnsubscribePacket;

            Assert.IsNotNull(unsubscribePacket);
            // todo verify

            await channel.WriteAndFlushAsync(UnsubAckPacket.InResponseTo(unsubscribePacket));

            var publishQos0Packet = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket;

            Assert.IsNotNull(publishQos0Packet);
            // todo verify

            var publishQos1Packet = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket;

            Assert.IsNotNull(publishQos1Packet);
            // todo verify

            int publishQos1PacketId = GetRandomPacketId();
            await channel.WriteAndFlushManyAsync(
                PubAckPacket.InResponseTo(publishQos1Packet),
                new PublishPacket(QualityOfService.AtLeastOnce, false, false)
            {
                PacketId  = publishQos1PacketId,
                TopicName = PublishS2CQos1Topic,
                Payload   = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishS2CQos1Payload))
            });

            var pubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as PubAckPacket;

            Assert.AreEqual(publishQos1PacketId, pubAckPacket.PacketId);

            var disconnectPacket = await readListener.ReceiveAsync(DefaultTimeout) as DisconnectPacket;

            Assert.IsNotNull(disconnectPacket);
        }
        protected override async Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId,
            CancellationToken cancellationToken)
        {
            await GetSubscribeSteps(channel, readHandler, clientId);

            while (!cancellationToken.IsCancellationRequested)
            {
                await GetPublishSteps(channel, readHandler, clientId, QualityOfService.AtLeastOnce, "devices/{0}/messages/events", 1, 138, 353);

                await channel.EventLoop.ScheduleAsync(() => { }, TimeSpan.FromMinutes(1), cancellationToken);
            }
        }
        protected override async Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId,
                                                  CancellationToken cancellationToken)
        {
            await GetSubscribeSteps(channel, readHandler, clientId);

            while (!cancellationToken.IsCancellationRequested)
            {
                await GetPublishSteps(channel, readHandler, clientId, QualityOfService.AtLeastOnce, "devices/{0}/messages/events", 1, 138, 353);

                await channel.EventLoop.ScheduleAsync(() => { }, TimeSpan.FromMinutes(1), cancellationToken);
            }
        }
        protected static async Task GetSubscribeSteps(IChannel channel, ReadListeningHandler readHandler, string clientId, string topicNamePattern)
        {
            int subscribePacketId = Random.Next(1, ushort.MaxValue);
            await channel.WriteAndFlushAsync(
                new SubscribePacket(
                    subscribePacketId,
                    new SubscriptionRequest(string.Format(topicNamePattern, clientId), QualityOfService.ExactlyOnce)));

            object message = await readHandler.ReceiveAsync();

            var subackPacket = message as SubAckPacket;

            if (subackPacket == null)
            {
                throw new InvalidOperationException(string.Format("{1}: Expected SUBACK, received {0}", message, clientId));
            }
            else if (subackPacket.PacketId == subscribePacketId && subackPacket.ReturnCodes[0] > QualityOfService.ExactlyOnce)
            {
                throw new InvalidOperationException($"{clientId}: Expected successful SUBACK({subscribePacketId.ToString()}), received SUBACK({subackPacket.PacketId.ToString()}) with QoS={subackPacket.ReturnCodes[0].ToString()}");
            }
        }
        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;
        }
        static async Task RunWebSocketServer()
        {
            HttpListenerContext context = await listener.GetContextAsync();

            if (!context.Request.IsWebSocketRequest)
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                context.Response.Close();
            }

            HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(WebSocketConstants.SubProtocols.Mqtt, 8 * 1024, TimeSpan.FromMinutes(5));

            serverListener         = new ReadListeningHandler();
            serverWebSocketChannel = new ServerWebSocketChannel(null, webSocketContext.WebSocket, context.Request.RemoteEndPoint);
            serverWebSocketChannel
            .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
            .Option(ChannelOption.AutoRead, true)
            .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
            .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default);
            serverWebSocketChannel.Pipeline.AddLast("server logger", new LoggingHandler("SERVER"));
            serverWebSocketChannel.Pipeline.AddLast(
                MqttEncoder.Instance,
                new MqttDecoder(true, 256 * 1024),
                serverListener);
            var workerGroup = new MultithreadEventLoopGroup();
            await workerGroup.GetNext().RegisterAsync(serverWebSocketChannel);

            while (true)
            {
                if (done)
                {
                    break;
                }

                await Task.Delay(TimeSpan.FromSeconds(2));
            }
        }
        protected static async Task GetPublishSteps(IChannel channel, ReadListeningHandler readHandler, string clientId, QualityOfService qos,
                                                    string topicNamePattern, int count, int minPayloadSize, int maxPayloadSize)
        {
            Contract.Requires(count > 0);
            Contract.Requires(qos < QualityOfService.ExactlyOnce);

            PublishPacket[] publishPackets = Enumerable.Repeat(0, count)
                                             .Select(_ => new PublishPacket(qos, false, false)
            {
                TopicName = string.Format(topicNamePattern, clientId),
                PacketId  = Random.Next(1, ushort.MaxValue),
                Payload   = GetPayloadBuffer(Random.Next(minPayloadSize, maxPayloadSize))
            })
                                             .ToArray();
            await channel.WriteAndFlushManyAsync(publishPackets);

            if (qos == QualityOfService.AtMostOnce)
            {
                return;
            }

            int acked = 0;

            do
            {
                object receivedMessage = await readHandler.ReceiveAsync();

                var pubackPacket = receivedMessage as PubAckPacket;
                if (pubackPacket == null || pubackPacket.PacketId != publishPackets[acked].PacketId)
                {
                    throw new InvalidOperationException($"{clientId}: Expected PUBACK({publishPackets[acked].PacketId.ToString()}), received {receivedMessage}");
                }

                acked++;
            }while (acked < count);
        }
 protected static Task GetSubscribeSteps(IChannel channel, ReadListeningHandler readHandler, string clientId)
 {
     return GetSubscribeSteps(channel, readHandler, clientId, "devices/{0}/messages/devicebound");
 }
        static async Task RunMqttClientScenarioAsync(IChannel channel, ReadListeningHandler readListener)
        {
            await channel.WriteAndFlushAsync(new ConnectPacket
            {
                ClientId      = ClientId,
                Username      = "******",
                Password      = "******",
                WillTopicName = "last/word",
                WillMessage   = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("oops"))
            });

            var connAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as ConnAckPacket;

            Assert.IsNotNull(connAckPacket);
            Assert.AreEqual(ConnectReturnCode.Accepted, connAckPacket.ReturnCode);

            int subscribePacketId   = GetRandomPacketId();
            int unsubscribePacketId = GetRandomPacketId();
            await channel.WriteAndFlushManyAsync(
                new SubscribePacket(subscribePacketId,
                                    new SubscriptionRequest(SubscribeTopicFilter1, QualityOfService.ExactlyOnce),
                                    new SubscriptionRequest(SubscribeTopicFilter2, QualityOfService.AtLeastOnce),
                                    new SubscriptionRequest("for/unsubscribe", QualityOfService.AtMostOnce)),
                new UnsubscribePacket(unsubscribePacketId, "for/unsubscribe"));

            var subAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as SubAckPacket;

            Assert.IsNotNull(subAckPacket);
            Assert.AreEqual(subscribePacketId, subAckPacket.PacketId);
            Assert.AreEqual(3, subAckPacket.ReturnCodes.Count);
            Assert.AreEqual(QualityOfService.ExactlyOnce, subAckPacket.ReturnCodes[0]);
            Assert.AreEqual(QualityOfService.AtLeastOnce, subAckPacket.ReturnCodes[1]);
            Assert.AreEqual(QualityOfService.AtMostOnce, subAckPacket.ReturnCodes[2]);

            var unsubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as UnsubAckPacket;

            Assert.IsNotNull(unsubAckPacket);
            Assert.AreEqual(unsubscribePacketId, unsubAckPacket.PacketId);

            int publishQoS1PacketId = GetRandomPacketId();
            await channel.WriteAndFlushManyAsync(
                new PublishPacket(QualityOfService.AtMostOnce, false, false)
            {
                TopicName = PublishC2STopic,
                Payload   = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos0Payload))
            },
                new PublishPacket(QualityOfService.AtLeastOnce, false, false)
            {
                PacketId  = publishQoS1PacketId,
                TopicName = PublishC2SQos1Topic,
                Payload   = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos1Payload))
            });

            //new PublishPacket(QualityOfService.AtLeastOnce, false, false) { TopicName = "feedback/qos/One", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("QoS 1 test. Different data length.")) });

            var pubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as PubAckPacket;

            Assert.IsNotNull(pubAckPacket);
            Assert.AreEqual(publishQoS1PacketId, pubAckPacket.PacketId);

            var publishPacket = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket;

            Assert.IsNotNull(publishPacket);
            Assert.AreEqual(QualityOfService.AtLeastOnce, publishPacket.QualityOfService);
            Assert.AreEqual(PublishS2CQos1Topic, publishPacket.TopicName);
            Assert.AreEqual(PublishS2CQos1Payload, publishPacket.Payload.ToString(Encoding.UTF8));

            await channel.WriteAndFlushManyAsync(
                PubAckPacket.InResponseTo(publishPacket),
                DisconnectPacket.Instance);
        }
Esempio n. 16
0
        public async Task EchoServerAndClient()
        {
            var         testPromise     = new DefaultPromise();
            var         tlsCertificate  = TestResourceHelper.GetTestCertificate();
            Func <Task> closeServerFunc = await this.StartServerAsync(true, ch =>
            {
                ch.Pipeline.AddLast("server logger", new LoggingHandler("SERVER"));
                ch.Pipeline.AddLast("server tls", TlsHandler.Server(tlsCertificate));
                ch.Pipeline.AddLast("server logger2", new LoggingHandler("SER***"));
                ch.Pipeline.AddLast("server prepender", new LengthFieldPrepender2(2));
                ch.Pipeline.AddLast("server decoder", new LengthFieldBasedFrameDecoder2(ushort.MaxValue, 0, 2, 0, 2));
                ch.Pipeline.AddLast(new EchoChannelHandler());
            }, testPromise);

            var       group        = new MultithreadEventLoopGroup();
            var       readListener = new ReadListeningHandler(DefaultTimeout);
            Bootstrap b            = new Bootstrap()
                                     .Group(group)
                                     .Channel <TcpSocketChannel>()
                                     .Option(ChannelOption.TcpNodelay, true)
                                     .Handler(new ActionChannelInitializer <ISocketChannel>(ch =>
            {
                string targetHost     = tlsCertificate.GetNameInfo(X509NameType.DnsName, false);
                var clientTlsSettings = new ClientTlsSettings(targetHost);
                ch.Pipeline.AddLast("client logger", new LoggingHandler("CLIENT"));
                ch.Pipeline.AddLast("client tls", new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), clientTlsSettings));
                ch.Pipeline.AddLast("client logger2", new LoggingHandler("CLI***"));
                ch.Pipeline.AddLast("client prepender", new LengthFieldPrepender2(2));
                ch.Pipeline.AddLast("client decoder", new LengthFieldBasedFrameDecoder2(ushort.MaxValue, 0, 2, 0, 2));
                ch.Pipeline.AddLast(readListener);
            }));

            this.Output.WriteLine("Configured Bootstrap: {0}", b);

            IChannel clientChannel = null;

            try
            {
                clientChannel = await b.ConnectAsync(IPAddress.Loopback, Port);

                this.Output.WriteLine("Connected channel: {0}", clientChannel);

                string[] messages = { "message 1", string.Join(",", Enumerable.Range(1, 300)) };
                foreach (string message in messages)
                {
                    await clientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(message))).WithTimeout(DefaultTimeout);

                    var responseMessage = Assert.IsAssignableFrom <IByteBuffer>(await readListener.ReceiveAsync());
                    Assert.Equal(message, responseMessage.ToString(Encoding.UTF8));
                }

                testPromise.TryComplete();
                await testPromise.Task.WithTimeout(TimeSpan.FromMinutes(5));
            }
            finally
            {
                Task serverCloseTask = closeServerFunc();
                clientChannel?.CloseAsync().Wait(TimeSpan.FromSeconds(5));
                group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(5)).Wait(TimeSpan.FromSeconds(10));
                if (!serverCloseTask.Wait(ShutdownTimeout))
                {
                    this.Output.WriteLine("Didn't stop in time.");
                }
            }
        }
Esempio n. 17
0
        public async Task MqttServerAndClient()
        {
            var testPromise = new DefaultPromise();

            var         tlsCertificate     = TestResourceHelper.GetTestCertificate();
            var         serverReadListener = new ReadListeningHandler();
            IChannel    serverChannel      = null;
            Func <Task> closeServerFunc    = await this.StartServerAsync(true, ch =>
            {
                serverChannel = ch;
                ch.Pipeline.AddLast("server logger", new LoggingHandler("SERVER"));
                ch.Pipeline.AddLast("server tls", TlsHandler.Server(tlsCertificate));
                ch.Pipeline.AddLast("server logger2", new LoggingHandler("SER***"));
                ch.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(true, 256 * 1024),
                    serverReadListener);
            }, testPromise);

            var       group = new MultithreadEventLoopGroup();
            var       clientReadListener = new ReadListeningHandler();
            Bootstrap b = new Bootstrap()
                          .Group(group)
                          .Channel <TcpSocketChannel>()
                          .Option(ChannelOption.TcpNodelay, true)
                          .Handler(new ActionChannelInitializer <ISocketChannel>(ch =>
            {
                string targetHost     = tlsCertificate.GetNameInfo(X509NameType.DnsName, false);
                var clientTlsSettings = new ClientTlsSettings(targetHost);

                ch.Pipeline.AddLast("client logger", new LoggingHandler("CLIENT"));
                ch.Pipeline.AddLast("client tls", new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), clientTlsSettings));
                ch.Pipeline.AddLast("client logger2", new LoggingHandler("CLI***"));
                ch.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(false, 256 * 1024),
                    clientReadListener);
            }));

            this.Output.WriteLine("Configured Bootstrap: {0}", b);

            IChannel clientChannel = null;

            try
            {
                clientChannel = await b.ConnectAsync(IPAddress.Loopback, Port);

                this.Output.WriteLine("Connected channel: {0}", clientChannel);

                await Task.WhenAll(this.RunMqttClientScenarioAsync(clientChannel, clientReadListener), this.RunMqttServerScenarioAsync(serverChannel, serverReadListener))
                .WithTimeout(TimeSpan.FromMinutes(5));

                testPromise.TryComplete();
                await testPromise.Task;
            }
            finally
            {
                Task serverCloseTask = closeServerFunc();
                clientChannel?.CloseAsync().Wait(TimeSpan.FromSeconds(5));
                group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(5)).Wait(TimeSpan.FromSeconds(10));
                if (!serverCloseTask.Wait(ShutdownTimeout))
                {
                    this.Output.WriteLine("Didn't stop in time.");
                }
            }
        }
        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;
        }
        static async Task RunMqttClientScenarioAsync(IChannel channel, ReadListeningHandler readListener)
        {
            await channel.WriteAndFlushAsync(new ConnectPacket
            {
                ClientId = ClientId,
                Username = "******",
                Password = "******",
                WillTopicName = "last/word",
                WillMessage = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("oops"))
            });

            var connAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as ConnAckPacket;
            Assert.IsNotNull(connAckPacket);
            Assert.AreEqual(ConnectReturnCode.Accepted, connAckPacket.ReturnCode);

            int subscribePacketId = GetRandomPacketId();
            int unsubscribePacketId = GetRandomPacketId();
            await channel.WriteAndFlushManyAsync(
                new SubscribePacket(subscribePacketId,
                    new SubscriptionRequest(SubscribeTopicFilter1, QualityOfService.ExactlyOnce),
                    new SubscriptionRequest(SubscribeTopicFilter2, QualityOfService.AtLeastOnce),
                    new SubscriptionRequest("for/unsubscribe", QualityOfService.AtMostOnce)),
                new UnsubscribePacket(unsubscribePacketId, "for/unsubscribe"));

            var subAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as SubAckPacket;
            Assert.IsNotNull(subAckPacket);
            Assert.AreEqual(subscribePacketId, subAckPacket.PacketId);
            Assert.AreEqual(3, subAckPacket.ReturnCodes.Count);
            Assert.AreEqual(QualityOfService.ExactlyOnce, subAckPacket.ReturnCodes[0]);
            Assert.AreEqual(QualityOfService.AtLeastOnce, subAckPacket.ReturnCodes[1]);
            Assert.AreEqual(QualityOfService.AtMostOnce, subAckPacket.ReturnCodes[2]);

            var unsubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as UnsubAckPacket;
            Assert.IsNotNull(unsubAckPacket);
            Assert.AreEqual(unsubscribePacketId, unsubAckPacket.PacketId);

            int publishQoS1PacketId = GetRandomPacketId();
            await channel.WriteAndFlushManyAsync(
                new PublishPacket(QualityOfService.AtMostOnce, false, false)
                {
                    TopicName = PublishC2STopic,
                    Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos0Payload))
                },
                new PublishPacket(QualityOfService.AtLeastOnce, false, false)
                {
                    PacketId = publishQoS1PacketId,
                    TopicName = PublishC2SQos1Topic,
                    Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos1Payload))
                });
            //new PublishPacket(QualityOfService.AtLeastOnce, false, false) { TopicName = "feedback/qos/One", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("QoS 1 test. Different data length.")) });

            var pubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as PubAckPacket;
            Assert.IsNotNull(pubAckPacket);
            Assert.AreEqual(publishQoS1PacketId, pubAckPacket.PacketId);

            var publishPacket = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket;
            Assert.IsNotNull(publishPacket);
            Assert.AreEqual(QualityOfService.AtLeastOnce, publishPacket.QualityOfService);
            Assert.AreEqual(PublishS2CQos1Topic, publishPacket.TopicName);
            Assert.AreEqual(PublishS2CQos1Payload, publishPacket.Payload.ToString(Encoding.UTF8));

            await channel.WriteAndFlushManyAsync(
                PubAckPacket.InResponseTo(publishPacket),
                DisconnectPacket.Instance);
        }
       static async Task RunMqttServerScenarioAsync(IChannel channel, ReadListeningHandler readListener)
        {
            var connectPacket = await readListener.ReceiveAsync(DefaultTimeout) as ConnectPacket;
            Assert.IsNotNull(connectPacket, "Must be a Connect pkt");
            // todo verify

            await channel.WriteAndFlushAsync(new ConnAckPacket
            {
                ReturnCode = ConnectReturnCode.Accepted,
                SessionPresent = true
            });

            var subscribePacket = await readListener.ReceiveAsync(DefaultTimeout) as SubscribePacket;
            Assert.IsNotNull(subscribePacket);
            // todo verify

            await channel.WriteAndFlushAsync(SubAckPacket.InResponseTo(subscribePacket, QualityOfService.ExactlyOnce));

            var unsubscribePacket = await readListener.ReceiveAsync(DefaultTimeout) as UnsubscribePacket;
            Assert.IsNotNull(unsubscribePacket);
            // todo verify

            await channel.WriteAndFlushAsync(UnsubAckPacket.InResponseTo(unsubscribePacket));

            var publishQos0Packet = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket;
            Assert.IsNotNull(publishQos0Packet);
            // todo verify

            var publishQos1Packet = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket;
            Assert.IsNotNull(publishQos1Packet);
            // todo verify

            int publishQos1PacketId = GetRandomPacketId();
            await channel.WriteAndFlushManyAsync(
                PubAckPacket.InResponseTo(publishQos1Packet),
                new PublishPacket(QualityOfService.AtLeastOnce, false, false)
                {
                    PacketId = publishQos1PacketId,
                    TopicName = PublishS2CQos1Topic,
                    Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishS2CQos1Payload))
                });

            var pubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as PubAckPacket;
            Assert.AreEqual(publishQos1PacketId, pubAckPacket.PacketId);

            var disconnectPacket = await readListener.ReceiveAsync(DefaultTimeout) as DisconnectPacket;
            Assert.IsNotNull(disconnectPacket);
        }
        async Task GetCompleteScenarioAsync(IChannel channel, ReadListeningHandler readHandler, string clientId, string password, CancellationToken cancellationToken)
        {
            await channel.WriteAndFlushAsync(new ConnectPacket
            {
                ClientId = clientId,
                CleanSession = false,
                HasUsername = true,
                Username = clientId,
                HasPassword = true,
                Password = password,
                KeepAliveInSeconds = 120
            });

            object message = await readHandler.ReceiveAsync();
            var connackPacket = message as ConnAckPacket;
            if (connackPacket == null)
            {
                throw new InvalidOperationException(string.Format("{1}: Expected CONNACK, received {0}", message, clientId));
            }
            else if (connackPacket.ReturnCode != ConnectReturnCode.Accepted)
            {
                throw new InvalidOperationException(string.Format("{1}: Expected successful CONNACK, received CONNACK with return code of {0}", connackPacket.ReturnCode, clientId));
            }

            await this.GetScenario(channel, readHandler, clientId, cancellationToken);
        }
       static async Task RunWebSocketServer()
        {
            HttpListenerContext context = await listener.GetContextAsync();
            if (!context.Request.IsWebSocketRequest)
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                context.Response.Close();
            }

            HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(WebSocketConstants.SubProtocols.Mqtt, 8 * 1024, TimeSpan.FromMinutes(5));

            serverListener = new ReadListeningHandler();
            serverWebSocketChannel = new ServerWebSocketChannel(null, webSocketContext.WebSocket, context.Request.RemoteEndPoint);
            serverWebSocketChannel
                .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
                .Option(ChannelOption.AutoRead, true)
                .Option(ChannelOption.RcvbufAllocator, new AdaptiveRecvByteBufAllocator())
                .Option(ChannelOption.MessageSizeEstimator, DefaultMessageSizeEstimator.Default);
            serverWebSocketChannel.Pipeline.AddLast("server logger", new LoggingHandler("SERVER"));
            serverWebSocketChannel.Pipeline.AddLast(
                MqttEncoder.Instance,
                new MqttDecoder(true, 256 * 1024),
                serverListener);
            var workerGroup = new MultithreadEventLoopGroup();
            await workerGroup.GetNext().RegisterAsync(serverWebSocketChannel);

           while (true)
           {
               if (done)
               {
                   break;
               }

               await Task.Delay(TimeSpan.FromSeconds(2));
           }
        }
        protected static async Task GetPublishSteps(IChannel channel, ReadListeningHandler readHandler, string clientId, QualityOfService qos,
            string topicNamePattern, int count, int minPayloadSize, int maxPayloadSize)
        {
            Contract.Requires(count > 0);
            Contract.Requires(qos < QualityOfService.ExactlyOnce);

            PublishPacket[] publishPackets = Enumerable.Repeat(0, count)
                .Select(_ => new PublishPacket(qos, false, false)
                {
                    TopicName = string.Format(topicNamePattern, clientId),
                    PacketId = Random.Next(1, ushort.MaxValue),
                    Payload = GetPayloadBuffer(Random.Next(minPayloadSize, maxPayloadSize))
                })
                .ToArray();
            await channel.WriteAndFlushManyAsync(publishPackets);

            if (qos == QualityOfService.AtMostOnce)
            {
                return;
            }

            int acked = 0;
            do
            {
                object receivedMessage = await readHandler.ReceiveAsync();
                var pubackPacket = receivedMessage as PubAckPacket;
                if (pubackPacket == null || pubackPacket.PacketId != publishPackets[acked].PacketId)
                {
                    throw new InvalidOperationException($"{clientId}: Expected PUBACK({publishPackets[acked].PacketId.ToString()}), received {receivedMessage}");
                }

                acked++;
            }
            while (acked < count);
        }
 protected static Task GetSubscribeSteps(IChannel channel, ReadListeningHandler readHandler, string clientId)
 {
     return(GetSubscribeSteps(channel, readHandler, clientId, "devices/{0}/messages/devicebound"));
 }
 protected virtual Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId,
     CancellationToken cancellationToken)
 {
     return TaskEx.Completed;
 }
        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;
        }
 protected static async Task GetSubscribeSteps(IChannel channel, ReadListeningHandler readHandler, string clientId, string topicNamePattern)
 {
     int subscribePacketId = Random.Next(1, ushort.MaxValue);
     await channel.WriteAndFlushAsync(
         new SubscribePacket(
             subscribePacketId,
             new SubscriptionRequest(string.Format(topicNamePattern, clientId), QualityOfService.ExactlyOnce)));
     object message = await readHandler.ReceiveAsync();
     var subackPacket = message as SubAckPacket;
     if (subackPacket == null)
     {
         throw new InvalidOperationException(string.Format("{1}: Expected SUBACK, received {0}", message, clientId));
     }
     else if (subackPacket.PacketId == subscribePacketId && subackPacket.ReturnCodes[0] > QualityOfService.ExactlyOnce)
     {
         throw new InvalidOperationException($"{clientId}: Expected successful SUBACK({subscribePacketId.ToString()}), received SUBACK({subackPacket.PacketId.ToString()}) with QoS={subackPacket.ReturnCodes[0].ToString()}");
     }
 }
 protected virtual Task GetScenario(IChannel channel, ReadListeningHandler readHandler, string clientId,
                                    CancellationToken cancellationToken)
 {
     return(TaskEx.Completed);
 }