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; }
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)); }))); }
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; }
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)); }))); }
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); }
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; }