Example #1
0
 public MqttWebSocketListener(
     Settings settings,
     MessagingBridgeFactoryFunc messagingBridgeFactoryFunc,
     IAuthenticator authenticator,
     IUsernameParser usernameParser,
     IClientCredentialsFactory clientCredentialsFactory,
     Func <ISessionStatePersistenceProvider> sessionProviderFactory,
     IEventLoopGroup workerGroup,
     IByteBufferAllocator byteBufferAllocator,
     bool autoRead,
     int mqttDecoderMaxMessageSize,
     bool clientCertAuthAllowed,
     IMetadataStore metadataStore)
 {
     this.settings = Preconditions.CheckNotNull(settings, nameof(settings));
     this.messagingBridgeFactoryFunc = Preconditions.CheckNotNull(messagingBridgeFactoryFunc, nameof(messagingBridgeFactoryFunc));
     this.authenticator            = Preconditions.CheckNotNull(authenticator, nameof(authenticator));
     this.usernameParser           = Preconditions.CheckNotNull(usernameParser, nameof(usernameParser));
     this.clientCredentialsFactory = Preconditions.CheckNotNull(clientCredentialsFactory, nameof(clientCredentialsFactory));
     this.sessionProviderFactory   = Preconditions.CheckNotNull(sessionProviderFactory, nameof(sessionProviderFactory));
     this.workerGroup               = Preconditions.CheckNotNull(workerGroup, nameof(workerGroup));
     this.byteBufferAllocator       = Preconditions.CheckNotNull(byteBufferAllocator, nameof(byteBufferAllocator));
     this.autoRead                  = autoRead;
     this.mqttDecoderMaxMessageSize = mqttDecoderMaxMessageSize;
     this.clientCertAuthAllowed     = clientCertAuthAllowed;
     this.metadataStore             = Preconditions.CheckNotNull(metadataStore, nameof(metadataStore));
 }
        public MqttAdapter(
            Settings settings,
            ISessionStatePersistenceProvider sessionStateManager,
            IDeviceIdentityProvider authProvider,
            IQos2StatePersistenceProvider qos2StateProvider,
            MessagingBridgeFactoryFunc messagingBridgeFactory)
        {
            Contract.Requires(settings != null);
            Contract.Requires(sessionStateManager != null);
            Contract.Requires(authProvider != null);
            Contract.Requires(messagingBridgeFactory != null);

            this.lifetimeCancellation = new CancellationTokenSource();

            if (qos2StateProvider != null)
            {
                this.maxSupportedQosToClient = QualityOfService.ExactlyOnce;
                this.qos2StateProvider       = qos2StateProvider;
            }
            else
            {
                this.maxSupportedQosToClient = QualityOfService.AtLeastOnce;
            }

            this.settings               = settings;
            this.sessionStateManager    = sessionStateManager;
            this.authProvider           = authProvider;
            this.messagingBridgeFactory = messagingBridgeFactory;
        }
Example #3
0
        ServerBootstrap SetupBootstrap()
        {
            int      maxInboundMessageSize = this.settingsProvider.GetIntegerSetting("MaxInboundMessageSize", 256 * 1024);
            int      connectionPoolSize    = this.settingsProvider.GetIntegerSetting("IotHubClient.ConnectionPoolSize", DefaultConnectionPoolSize);
            TimeSpan connectionIdleTimeout = this.settingsProvider.GetTimeSpanSetting("IotHubClient.ConnectionIdleTimeout", DefaultConnectionIdleTimeout);
            string   connectionString      = this.iotHubClientSettings.IotHubConnectionString;

            Func <IDeviceIdentity, Task <IMessagingServiceClient> > deviceClientFactory = IotHubClient.PreparePoolFactory(connectionString, connectionPoolSize,
                                                                                                                          connectionIdleTimeout, this.iotHubClientSettings, PooledByteBufferAllocator.Default, this.topicNameConverter);
            MessagingBridgeFactoryFunc bridgeFactory = async deviceIdentity => new SingleClientMessagingBridge(deviceIdentity, await deviceClientFactory(deviceIdentity));

            return(new ServerBootstrap()
                   .Group(this.parentEventLoopGroup, this.eventLoopGroup)
                   .Option(ChannelOption.SoBacklog, ListenBacklogSize)
                   .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
                   .ChildOption(ChannelOption.AutoRead, false)
                   .Channel <TcpServerSocketChannel>()
                   .ChildHandler(new ActionChannelInitializer <ISocketChannel>(channel =>
            {
                channel.Pipeline.AddLast(TlsHandler.Server(this.tlsCertificate));
                channel.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(true, maxInboundMessageSize),
                    new MqttAdapter(
                        this.settings,
                        this.sessionStateManager,
                        this.authProvider,
                        this.qos2StateProvider,
                        bridgeFactory));
            })));
        }
        ServerBootstrap SetupBootstrap(ChannelHandlerAdapter firstHandler)
        {
            Contract.Requires(firstHandler != null);

            return(new ServerBootstrap()
                   .Group(this.parentEventLoopGroup, this.eventLoopGroup)
                   .Option(ChannelOption.SoBacklog, ListenBacklogSize)
                   .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
                   .Channel <TcpServerSocketChannel>()
                   .ChildHandler(new ActionChannelInitializer <IChannel>(channel =>
            {
                int connectionPoolSize = this.settingsProvider.GetIntegerSetting("IotHubClient.ConnectionPoolSize", DefaultConnectionPoolSize);
                TimeSpan connectionIdleTimeout = this.settingsProvider.GetTimeSpanSetting("IotHubClient.ConnectionIdleTimeout", DefaultConnectionIdleTimeout);
                string connectionString = this.iotHubClientSettings.IotHubConnectionString;
                int maxInboundMessageSize = this.settingsProvider.GetIntegerSetting("MaxInboundMessageSize", 256 * 1024);

                var messagingAddressConverter = new IoTHubProvider.Addressing.MessageAddressConverter();
                Func <IDeviceIdentity, Task <ITcpIoTHubMessagingServiceClient> > deviceClientFactory
                    = IotHubClient.PreparePoolFactory(connectionString, connectionPoolSize, connectionIdleTimeout, this.iotHubClientSettings);

                MessagingBridgeFactoryFunc bridgeFactory
                    = async deviceIdentity => new SingleClientMessagingBridge(deviceIdentity, await deviceClientFactory(deviceIdentity));

                channel.Pipeline.AddLast(firstHandler);
                channel.Pipeline.AddLast(DeviceTopicDecoder.HandlerName, new DeviceTopicDecoder(this.credentialProvider, messagingAddressConverter.TopicTemplates));
                channel.Pipeline.AddLast(SocketIoTHubAdapter.HandlerName, new SocketIoTHubAdapter(this.settings, credentialProvider, this.authProvider, bridgeFactory));
            })));
        }
        async Task EnsureServerInitializedAsync()
        {
            if (this.ServerAddress != null)
            {
                return;
            }

            int threadCount   = Environment.ProcessorCount;
            var executorGroup = new MultithreadEventLoopGroup(threadCount);
            BlobSessionStatePersistenceProvider sessionStateProvider = await BlobSessionStatePersistenceProvider.CreateAsync(
                this.settingsProvider.GetSetting("BlobSessionStatePersistenceProvider.StorageConnectionString"),
                this.settingsProvider.GetSetting("BlobSessionStatePersistenceProvider.StorageContainerName"));

            TableQos2StatePersistenceProvider qos2StateProvider = await TableQos2StatePersistenceProvider.CreateAsync(
                this.settingsProvider.GetSetting("TableQos2StatePersistenceProvider.StorageConnectionString"),
                this.settingsProvider.GetSetting("TableQos2StatePersistenceProvider.StorageTableName"));

            var settings             = new Settings(this.settingsProvider);
            var iotHubClientSettings = new IotHubClientSettings(this.settingsProvider);
            var authProvider         = new SasTokenDeviceIdentityProvider();
            var topicNameRouter      = new ConfigurableMessageAddressConverter();

            var iotHubClientFactory = IotHubClient.PreparePoolFactory(iotHubClientSettings.IotHubConnectionString, 400, TimeSpan.FromMinutes(5),
                                                                      iotHubClientSettings, PooledByteBufferAllocator.Default, topicNameRouter);
            MessagingBridgeFactoryFunc bridgeFactory = async identity => new SingleClientMessagingBridge(identity, await iotHubClientFactory(identity));

            ServerBootstrap server = new ServerBootstrap()
                                     .Group(executorGroup)
                                     .Channel <TcpServerSocketChannel>()
                                     .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
                                     .ChildOption(ChannelOption.AutoRead, false)
                                     .ChildHandler(new ActionChannelInitializer <IChannel>(ch =>
            {
                ch.Pipeline.AddLast(TlsHandler.Server(this.tlsCertificate));
                ch.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(true, 256 * 1024),
                    new LoggingHandler("SERVER"),
                    new MqttAdapter(
                        settings,
                        sessionStateProvider,
                        authProvider,
                        qos2StateProvider,
                        bridgeFactory),
                    new XUnitLoggingHandler(this.output));
            }));

            IChannel serverChannel = await server.BindAsync(IPAddress.Any, this.ProtocolGatewayPort);

            this.ScheduleCleanup(async() =>
            {
                await serverChannel.CloseAsync();
                await executorGroup.ShutdownGracefullyAsync();
            });
            this.ServerAddress = IPAddress.Loopback;
        }
        public static MessagingBridgeFactoryFunc PrepareFactory(string baseConnectionString, int connectionPoolSize,
                                                                TimeSpan?connectionIdleTimeout, IotHubClientSettings settings, Action <IotHubBridge> initHandler)
        {
            MessagingBridgeFactoryFunc mqttCommunicatorFactory = async(deviceIdentity, cancellationToken) =>
            {
                var csb      = IotHubConnectionStringBuilder.Create(baseConnectionString);
                var identity = (IotHubDeviceIdentity)deviceIdentity;
                csb.AuthenticationMethod = DeriveAuthenticationMethod(csb.AuthenticationMethod, identity);
                csb.HostName             = identity.IotHubHostName;
                string connectionString = csb.ToString();
                var    bridge           = await CreateFromConnectionStringAsync(identity.Id, connectionString, connectionPoolSize, connectionIdleTimeout, settings, cancellationToken);

                initHandler(bridge);
                return(bridge);
            };

            return(mqttCommunicatorFactory);
        }
        ServerBootstrap SetupBootstrap()
        {
            // pull/customize configuration
            int      maxInboundMessageSize = this.settingsProvider.GetIntegerSetting("MaxInboundMessageSize", 256 * 1024);
            int      connectionPoolSize    = this.settingsProvider.GetIntegerSetting("IotHubClient.ConnectionPoolSize", DefaultConnectionPoolSize);
            TimeSpan connectionIdleTimeout = this.settingsProvider.GetTimeSpanSetting("IotHubClient.ConnectionIdleTimeout", DefaultConnectionIdleTimeout);
            string   connectionString      = this.iotHubClientSettings.IotHubConnectionString;

            // setup message processing logic
            var telemetryProcessing = TopicHandling.CompileParserFromUriTemplates(new[] { "devices/{deviceId}/messages/events" });
            var commandProcessing   = TopicHandling.CompileFormatterFromUriTemplate("devices/{deviceId}/messages/devicebound");
            MessagingBridgeFactoryFunc bridgeFactory = IotHubBridge.PrepareFactory(connectionString, connectionPoolSize,
                                                                                   connectionIdleTimeout, this.iotHubClientSettings, bridge =>
            {
                bridge.RegisterRoute(topic => true, new TelemetrySender(bridge, telemetryProcessing));                                                                    // handle all incoming messages with TelemetrySender
                bridge.RegisterSource(new CommandReceiver(bridge, PooledByteBufferAllocator.Default, commandProcessing));                                                 // handle device command queue
                bridge.RegisterSource(new MethodHandler("SendMessageToDevice", bridge, (request, dispatcher) => DispatchCommands(bridge.DeviceId, request, dispatcher))); // register
            });

            var acceptLimiter = new AcceptLimiter(MaxConcurrentAccepts);

            return(new ServerBootstrap()
                   .Group(this.parentEventLoopGroup, this.eventLoopGroup)
                   .Option(ChannelOption.SoBacklog, ListenBacklogSize)
                   .Option(ChannelOption.AutoRead, false)
                   .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
                   .ChildOption(ChannelOption.AutoRead, false)
                   .Channel <TcpServerSocketChannel>()
                   .Handler(acceptLimiter)
                   .ChildHandler(new ActionChannelInitializer <ISocketChannel>(channel =>
            {
                channel.Pipeline.AddLast(
                    TlsHandler.Server(this.tlsCertificate),
                    new AcceptLimiterTlsReleaseHandler(acceptLimiter),
                    MqttEncoder.Instance,
                    new MqttDecoder(true, maxInboundMessageSize),
                    new MqttAdapter(
                        this.settings,
                        this.sessionStateManager,
                        this.authProvider,
                        this.qos2StateProvider,
                        bridgeFactory));
            })));
        }
Example #8
0
 public MqttWebSocketListener(
     Settings settings,
     MessagingBridgeFactoryFunc messagingBridgeFactoryFunc,
     IDeviceIdentityProvider identityProvider,
     Func <ISessionStatePersistenceProvider> sessionProviderFactory,
     IEventLoopGroup workerGroup,
     IByteBufferAllocator byteBufferAllocator,
     bool autoRead,
     int mqttDecoderMaxMessageSize
     )
 {
     this.settings = Preconditions.CheckNotNull(settings, nameof(settings));
     this.messagingBridgeFactoryFunc = Preconditions.CheckNotNull(messagingBridgeFactoryFunc, nameof(messagingBridgeFactoryFunc));
     this.identityProvider           = Preconditions.CheckNotNull(identityProvider, nameof(identityProvider));
     this.sessionProviderFactory     = Preconditions.CheckNotNull(sessionProviderFactory, nameof(sessionProviderFactory));
     this.workerGroup               = Preconditions.CheckNotNull(workerGroup, nameof(workerGroup));
     this.byteBufferAllocator       = Preconditions.CheckNotNull(byteBufferAllocator, nameof(byteBufferAllocator));
     this.autoRead                  = autoRead;
     this.mqttDecoderMaxMessageSize = mqttDecoderMaxMessageSize;
 }
Example #9
0
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            var tenancyContext = context.GetAttribute <AbstractTenancyContext>(AttributeKey <AbstractTenancyContext> .ValueOf(AbstractTenancyContext.TENANCY_CONTEXT_KEY)).Get();

            this.messagingBridgeFactory = tenancyContext.IotBridgeFactory;


            var packets = message as IDictionary <PacketType, Packet>;

            if (packets == null || (packets != null && packets.Count <= 0))
            {
                Console.WriteLine(($"No messages (`{typeof(Packet).FullName}` ) received"));
                return;
            }

            var connectPacket = packets[PacketType.CONNECT] as ConnectPacket;
            var dataPacket    = packets[PacketType.D2C] as DeviceDataPacket;

            this.lastClientActivityTime = DateTime.Now;
            if (this.IsInState(StateFlags.Connected))   //Already Connected, process DeviceDataPacket
            {
                this.ProcessPacket(context, dataPacket);
            }
            else if (this.IsInState(StateFlags.ProcessingConnect))   //Connect processing in progress, queue newer connect requests
            {
                //TODO Implement queue/ priority queue based on supported cases
                Queue <Packet> queue = this.connectPendingQueue ?? (this.connectPendingQueue = new Queue <Packet>(4));
                queue.Enqueue(dataPacket);
            }
            else
            {
                //Not Connected and Not processing a connect - Use connect packet to create connection to IoTHub
                this.dataPacketWithConnect = dataPacket;
                this.ProcessPacket(context, connectPacket);
            }

            context.WriteAsync(message);
        }
        ServerBootstrap SetupBootstrap()
        {
            if (this.settings.DeviceReceiveAckCanTimeout && this.iotHubClientSettings.MaxPendingOutboundMessages > 1)
            {
                throw new InvalidOperationException("Cannot maintain ordering on retransmission with more than 1 allowed pending outbound message.");
            }

            int      maxInboundMessageSize = this.settingsProvider.GetIntegerSetting("MaxInboundMessageSize", 256 * 1024);
            int      connectionPoolSize    = this.settingsProvider.GetIntegerSetting("IotHubClient.ConnectionPoolSize", DefaultConnectionPoolSize);
            TimeSpan connectionIdleTimeout = this.settingsProvider.GetTimeSpanSetting("IotHubClient.ConnectionIdleTimeout", DefaultConnectionIdleTimeout);
            string   connectionString      = this.iotHubClientSettings.IotHubConnectionString;

            Func <IDeviceIdentity, Task <IMessagingServiceClient> > deviceClientFactory = IotHubClient.PreparePoolFactory(connectionString, connectionPoolSize,
                                                                                                                          connectionIdleTimeout, this.iotHubClientSettings, PooledByteBufferAllocator.Default, this.topicNameConverter);
            MessagingBridgeFactoryFunc bridgeFactory = async deviceIdentity => new SingleClientMessagingBridge(deviceIdentity, await deviceClientFactory(deviceIdentity));

            return(new ServerBootstrap()
                   .Group(this.parentEventLoopGroup, this.eventLoopGroup)
                   .Option(ChannelOption.SoBacklog, ListenBacklogSize)
                   .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
                   .ChildOption(ChannelOption.AutoRead, false)
                   .Channel <TcpServerSocketChannel>()
                   .ChildHandler(new ActionChannelInitializer <ISocketChannel>(channel =>
            {
                channel.Pipeline.AddLast(new DCMProvisionHandler());     //Adding this to the channel allows us to handle TLS traffic. If this is removed as well as the TLS/SSL channel then all interaction will be unencrypted
                //channel.Pipeline.AddLast(TlsHandler.Server(this.tlsCertificate)); //Removing this from the channel list removes TLS/SSL support
                channel.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(true, maxInboundMessageSize),
                    new MqttAdapter(
                        this.settings,
                        this.sessionStateManager,
                        this.authProvider,
                        this.qos2StateProvider,
                        bridgeFactory));
            })));
        }
Example #11
0
        ServerBootstrap SetupServerBootstrap()
        {
            int maxInboundMessageSize = this.settingsProvider.GetIntegerSetting("MaxInboundMessageSize", DefaultMaxInboundMessageSize);
            int threadCount           = this.settingsProvider.GetIntegerSetting("ThreadCount", DefaultThreadCount);
            int listenBacklogSize     = this.settingsProvider.GetIntegerSetting("ListenBacklogSize", DefaultListenBacklogSize);
            int parentEventLoopCount  = this.settingsProvider.GetIntegerSetting("EventLoopCount", DefaultParentEventLoopCount);
            var settings = new Settings(this.settingsProvider);

            MessagingBridgeFactoryFunc bridgeFactory = this.mqttConnectionProvider.Connect;

            var bootstrap = new ServerBootstrap();
            // multithreaded event loop that handles the incoming connection
            IEventLoopGroup parentEventLoopGroup = new MultithreadEventLoopGroup(parentEventLoopCount);

            // multithreaded event loop (worker) that handles the traffic of the accepted connections
            this.eventLoopGroup = new MultithreadEventLoopGroup(threadCount);

            bootstrap.Group(parentEventLoopGroup, this.eventLoopGroup)
            .Option(ChannelOption.SoBacklog, listenBacklogSize)
            // Allow listening socket to force bind to port if previous socket is still in TIME_WAIT
            // Fixes "address is already in use" errors
            .Option(ChannelOption.SoReuseaddr, true)
            .ChildOption(ChannelOption.Allocator, this.byteBufferAllocator)
            .ChildOption(ChannelOption.AutoRead, AutoRead)
            // channel that accepts incoming connections
            .Channel <TcpServerSocketChannel>()
            // Channel initializer, it is handler that is purposed to help configure a new channel
            .ChildHandler(
                new ActionChannelInitializer <ISocketChannel>(
                    channel =>
            {
                var identityProvider = new DeviceIdentityProvider(this.authenticator, this.clientCredentialsFactory, this.clientCertAuthAllowed);
                // configure the channel pipeline of the new Channel by adding handlers
                TlsSettings serverSettings = new ServerTlsSettings(
                    certificate: this.tlsCertificate,
                    negotiateClientCertificate: this.clientCertAuthAllowed
                    );

                channel.Pipeline.AddLast(
                    new TlsHandler(
                        stream =>
                        new SslStream(
                            stream,
                            true,
                            (sender, remoteCertificate, remoteChain, sslPolicyErrors) => this.RemoteCertificateValidationCallback(identityProvider, remoteCertificate, remoteChain)),
                        serverSettings));

                channel.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(true, maxInboundMessageSize),
                    new MqttAdapter(
                        settings,
                        this.sessionProvider,
                        identityProvider,
                        null,
                        bridgeFactory));
            }));

            var mqttWebSocketListener = new MqttWebSocketListener(
                settings,
                bridgeFactory,
                this.authenticator,
                this.clientCredentialsFactory,
                () => this.sessionProvider,
                new MultithreadEventLoopGroup(Environment.ProcessorCount),
                this.byteBufferAllocator,
                AutoRead,
                maxInboundMessageSize,
                this.clientCertAuthAllowed);

            this.webSocketListenerRegistry.TryRegister(mqttWebSocketListener);

            return(bootstrap);
        }
Example #12
0
        async Task EnsureServerInitializedAsync()
        {
            if (this.ServerAddress != null)
            {
                return;
            }

            int threadCount   = Environment.ProcessorCount;
            var executorGroup = new MultithreadEventLoopGroup(threadCount);
            BlobSessionStatePersistenceProvider sessionStateProvider = await BlobSessionStatePersistenceProvider.CreateAsync(
                this.settingsProvider.GetSetting("BlobSessionStatePersistenceProvider.StorageConnectionString"),
                this.settingsProvider.GetSetting("BlobSessionStatePersistenceProvider.StorageContainerName"));

            TableQos2StatePersistenceProvider qos2StateProvider = await TableQos2StatePersistenceProvider.CreateAsync(
                this.settingsProvider.GetSetting("TableQos2StatePersistenceProvider.StorageConnectionString"),
                this.settingsProvider.GetSetting("TableQos2StatePersistenceProvider.StorageTableName"));

            var settings             = new Settings(this.settingsProvider);
            var iotHubClientSettings = new IotHubClientSettings(this.settingsProvider);
            var authProvider         = new SasTokenDeviceIdentityProvider();

            var telemetryProcessing = TopicHandling.CompileParserFromUriTemplates(new[] { "devices/{deviceId}/messages/events" });
            var commandProcessing   = TopicHandling.CompileFormatterFromUriTemplate("devices/{deviceId}/messages/devicebound/{subTopic=}");
            MessagingBridgeFactoryFunc bridgeFactory = IotHubBridge.PrepareFactory(iotHubClientSettings.IotHubConnectionString, 400, TimeSpan.FromMinutes(5),
                                                                                   iotHubClientSettings, bridge =>
            {
                bridge.RegisterRoute(topic => true, new TelemetrySender(bridge, telemetryProcessing));                                                        // handle all incoming messages with TelemetrySender
                bridge.RegisterSource(new CommandReceiver(bridge, PooledByteBufferAllocator.Default, commandProcessing));                                     // handle device command queue
                bridge.RegisterSource(new MethodHandler("command", bridge, (request, dispatcher) => DispatchCommands(bridge.DeviceId, request, dispatcher))); // register
            });

            ServerBootstrap server = new ServerBootstrap()
                                     .Group(executorGroup)
                                     .Channel <TcpServerSocketChannel>()
                                     .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
                                     .ChildOption(ChannelOption.AutoRead, false)
                                     .ChildHandler(new ActionChannelInitializer <IChannel>(ch =>
            {
                ch.Pipeline.AddLast(TlsHandler.Server(this.tlsCertificate));
                ch.Pipeline.AddLast(
                    MqttEncoder.Instance,
                    new MqttDecoder(true, 256 * 1024),
                    new LoggingHandler("SERVER"),
                    new MqttAdapter(
                        settings,
                        sessionStateProvider,
                        authProvider,
                        qos2StateProvider,
                        bridgeFactory),
                    new XUnitLoggingHandler(this.output));
            }));

            IChannel serverChannel = await server.BindAsync(IPAddress.Any, this.ProtocolGatewayPort);

            this.ScheduleCleanup(async() =>
            {
                await serverChannel.CloseAsync();
                await executorGroup.ShutdownGracefullyAsync();
            });
            this.ServerAddress = IPAddress.Loopback;
        }