public MqttClientConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter, MqttClientSession session, MqttConnectionValidatorContext connectionValidatorContext, IMqttServerOptions serverOptions, MqttClientSessionsManager sessionsManager, IMqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger) { Session = session ?? throw new ArgumentNullException(nameof(session)); _serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); _channelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter)); _connectionValidatorContext = connectionValidatorContext ?? throw new ArgumentNullException(nameof(connectionValidatorContext)); _dataConverter = _channelAdapter.PacketFormatterAdapter.DataConverter; _endpoint = _channelAdapter.Endpoint; ConnectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket)); if (logger == null) { throw new ArgumentNullException(nameof(logger)); } _logger = logger.CreateScopedLogger(nameof(MqttClientConnection)); _connectedTimestamp = DateTime.UtcNow; LastPacketReceivedTimestamp = _connectedTimestamp; _lastNonKeepAlivePacketReceivedTimestamp = LastPacketReceivedTimestamp; }
public MqttClientConnection( MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter, MqttClientSession session, IMqttServerOptions serverOptions, MqttClientSessionsManager sessionsManager, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetChildLogger logger) { Session = session ?? throw new ArgumentNullException(nameof(session)); _serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); _channelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter)); _dataConverter = _channelAdapter.PacketFormatterAdapter.DataConverter; _endpoint = _channelAdapter.Endpoint; _connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket)); if (logger == null) { throw new ArgumentNullException(nameof(logger)); } _logger = logger.CreateChildLogger(nameof(MqttClientConnection)); _keepAliveMonitor = new MqttClientKeepAliveMonitor(_connectPacket.ClientId, StopAsync, _logger); _connectedTimestamp = DateTime.UtcNow; _lastPacketReceivedTimestamp = _connectedTimestamp; _lastNonKeepAlivePacketReceivedTimestamp = _lastPacketReceivedTimestamp; }
public MqttClientSubscriptionsManager(MqttClientSession clientSession, MqttServerEventDispatcher eventDispatcher, IMqttServerOptions serverOptions) { _clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); // TODO: Consider removing the server options here and build a new class "ISubscriptionInterceptor" and just pass it. The instance is generated in the root server class upon start. _serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _eventDispatcher = eventDispatcher ?? throw new ArgumentNullException(nameof(eventDispatcher)); }
public void EnqueueApplicationMessage(MqttClientSession senderClientSession, MqttPublishPacket publishPacket) { if (publishPacket == null) { throw new ArgumentNullException(nameof(publishPacket)); } _messageQueue.Add(new MqttEnqueuedApplicationMessage(senderClientSession, publishPacket), _cancellationToken); }
public MqttClientPendingPacketsQueue(IMqttServerOptions options, MqttClientSession clientSession, IMqttNetChildLogger logger) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } _options = options ?? throw new ArgumentNullException(nameof(options)); _clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); _logger = logger.CreateChildLogger(nameof(MqttClientPendingPacketsQueue)); }
private async Task <GetOrCreateClientSessionResult> GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket) { await _semaphore.WaitAsync().ConfigureAwait(false); try { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession); if (isSessionPresent) { if (connectPacket.CleanSession) { _sessions.Remove(connectPacket.ClientId); await clientSession.StopAsync().ConfigureAwait(false); clientSession.Dispose(); clientSession = null; _logger.Trace <MqttClientSessionsManager>("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { _logger.Trace <MqttClientSessionsManager>("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } var isExistingSession = true; if (clientSession == null) { isExistingSession = false; clientSession = new MqttClientSession(connectPacket.ClientId, _options, _retainedMessagesManager, _logger) { ApplicationMessageReceivedCallback = DispatchApplicationMessageAsync }; clientSession.SubscriptionsManager.TopicSubscribedCallback = ClientSubscribedTopicCallback; clientSession.SubscriptionsManager.TopicUnsubscribedCallback = ClientUnsubscribedTopicCallback; _sessions[connectPacket.ClientId] = clientSession; _logger.Trace <MqttClientSessionsManager>("Created a new session for client '{0}'.", connectPacket.ClientId); } return(new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }); } finally { _semaphore.Release(); } }
private MqttApplicationMessage InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { if (_options.ApplicationMessageInterceptor == null) { return(applicationMessage); } var interceptorContext = new MqttApplicationMessageInterceptorContext( senderClientSession.ClientId, applicationMessage); _options.ApplicationMessageInterceptor(interceptorContext); return(interceptorContext.ApplicationMessage); }
private MqttApplicationMessageInterceptorContext InterceptApplicationMessage(MqttClientSession sender, MqttApplicationMessage applicationMessage) { var interceptor = _options.ApplicationMessageInterceptor; if (interceptor == null) { return(null); } var interceptorContext = new MqttApplicationMessageInterceptorContext(sender?.ClientId, applicationMessage); interceptor(interceptorContext); return(interceptorContext); }
public void EnqueueApplicationMessage(MqttClientSession senderClientSession, MqttPublishPacket publishPacket) { if (publishPacket == null) { throw new ArgumentNullException(nameof(publishPacket)); } var checkSubscriptionsResult = _subscriptionsManager.CheckSubscriptions(publishPacket.Topic, publishPacket.QualityOfServiceLevel); if (!checkSubscriptionsResult.IsSubscribed) { return; } publishPacket = new MqttPublishPacket { Topic = publishPacket.Topic, Payload = publishPacket.Payload, QualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel, Retain = false, Dup = false }; if (publishPacket.QualityOfServiceLevel > 0) { publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(); } if (_options.ClientMessageQueueInterceptor != null) { var context = new MqttClientMessageQueueInterceptorContext( senderClientSession?.ClientId, ClientId, publishPacket.ToApplicationMessage()); _options.ClientMessageQueueInterceptor?.Invoke(context); if (!context.AcceptEnqueue || context.ApplicationMessage == null) { return; } publishPacket.Topic = context.ApplicationMessage.Topic; publishPacket.Payload = context.ApplicationMessage.Payload; publishPacket.QualityOfServiceLevel = context.ApplicationMessage.QualityOfServiceLevel; } _pendingPacketsQueue.Enqueue(publishPacket); }
private async Task <MqttClientConnection> CreateConnectionAsync(IMqttChannelAdapter channelAdapter, MqttConnectPacket connectPacket) { await _createConnectionGate.WaitAsync(_cancellationToken).ConfigureAwait(false); try { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var session); var isConnectionPresent = _connections.TryGetValue(connectPacket.ClientId, out var existingConnection); if (isConnectionPresent) { await existingConnection.StopAsync().ConfigureAwait(false); } if (isSessionPresent) { if (connectPacket.CleanSession) { session = null; _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId); } else { _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } if (session == null) { session = new MqttClientSession(connectPacket.ClientId, _eventDispatcher, _options, _logger); _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId); } var connection = new MqttClientConnection(connectPacket, channelAdapter, session, _options, this, _retainedMessagesManager, _logger); _connections[connection.ClientId] = connection; _sessions[session.ClientId] = session; return(connection); } finally { _createConnectionGate.Release(); } }
public async Task DispatchApplicationMessageAsync(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { try { var interceptorContext = InterceptApplicationMessage(senderClientSession, applicationMessage); if (interceptorContext.CloseConnection) { await senderClientSession.StopAsync().ConfigureAwait(false); } if (interceptorContext.ApplicationMessage == null || !interceptorContext.AcceptPublish) { return; } if (applicationMessage.Retain) { await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); } ApplicationMessageReceivedCallback?.Invoke(senderClientSession?.ClientId, applicationMessage); } catch (Exception exception) { _logger.Error <MqttClientSessionsManager>(exception, "Error while processing application message"); } await _semaphore.WaitAsync().ConfigureAwait(false); try { foreach (var clientSession in _sessions.Values) { await clientSession.EnqueueApplicationMessageAsync(applicationMessage); } } finally { _semaphore.Release(); } }
async Task <MqttClientConnection> CreateClientConnectionAsync(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter, Func <Task> onStart, Func <MqttClientDisconnectType, Task> onStop) { using (await _createConnectionGate.WaitAsync(_cancellationToken).ConfigureAwait(false)) { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var session); var isConnectionPresent = _connections.TryGetValue(connectPacket.ClientId, out var existingConnection); if (isConnectionPresent) { await existingConnection.StopAsync(true).ConfigureAwait(false); } if (isSessionPresent) { if (connectPacket.CleanSession) { session = null; _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId); } else { _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } if (session == null) { session = new MqttClientSession(connectPacket.ClientId, connectionValidatorContext.SessionItems, _eventDispatcher, _options, _retainedMessagesManager, _logger); _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId); } var connection = new MqttClientConnection(connectPacket, channelAdapter, session, _options, this, _retainedMessagesManager, onStart, onStop, _logger); _connections[connection.ClientId] = connection; _sessions[session.ClientId] = session; return(connection); } }
private PrepareClientSessionResult PrepareClientSession(MqttConnectPacket connectPacket) { lock (_sessions) { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession); if (isSessionPresent) { if (connectPacket.CleanSession) { _sessions.Remove(connectPacket.ClientId); clientSession.Stop(MqttClientDisconnectType.Clean); clientSession.Dispose(); clientSession = null; _logger.Verbose("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } var isExistingSession = true; if (clientSession == null) { isExistingSession = false; clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _retainedMessagesManager, _logger); _sessions[connectPacket.ClientId] = clientSession; _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId); } return(new PrepareClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }); } }
public async Task DispatchApplicationMessageAsync(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { try { applicationMessage = InterceptApplicationMessage(senderClientSession, applicationMessage); if (applicationMessage == null) { return; } if (applicationMessage.Retain) { await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); } _server.OnApplicationMessageReceived(senderClientSession?.ClientId, applicationMessage); } catch (Exception exception) { _logger.Error <MqttClientSessionsManager>(exception, "Error while processing application message"); } await _semaphore.WaitAsync().ConfigureAwait(false); try { foreach (var clientSession in _sessions.Values) { await clientSession.EnqueueApplicationMessageAsync(applicationMessage); } } finally { _semaphore.Release(); } }
public MqttClientSubscriptionsManager(MqttClientSession clientSession, MqttServerEventDispatcher eventDispatcher, IMqttServerOptions serverOptions) { _clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); _options = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _eventDispatcher = eventDispatcher ?? throw new ArgumentNullException(nameof(eventDispatcher)); }
public MqttClientSessionStatus(MqttClientSessionsManager sessionsManager, MqttClientSession session) { _sessionsManager = sessionsManager; _session = session; }
public async Task RunSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; MqttClientSession clientSession = null; try { if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false) is MqttConnectPacket connectPacket)) { throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1]."); } clientId = connectPacket.ClientId; // Switch to the required protocol version before sending any response. clientAdapter.PacketSerializer.ProtocolVersion = connectPacket.ProtocolVersion; var connectReturnCode = ValidateConnection(connectPacket); if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted) { await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket { ConnectReturnCode = connectReturnCode }).ConfigureAwait(false); return; } var result = await GetOrCreateClientSessionAsync(connectPacket).ConfigureAwait(false); clientSession = result.Session; await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket { ConnectReturnCode = connectReturnCode, IsSessionPresent = result.IsExistingSession }).ConfigureAwait(false); ClientConnectedCallback?.Invoke(new ConnectedMqttClient { ClientId = clientId, ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion }); await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); } catch (Exception exception) { _logger.Error <MqttClientSessionsManager>(exception, exception.Message); } finally { try { await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); } catch (Exception) { // ignored } ClientDisconnectedCallback?.Invoke(new ConnectedMqttClient { ClientId = clientId, ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion, PendingApplicationMessages = clientSession?.PendingMessagesQueue.Count ?? 0 }); } }
public MqttClientPendingMessagesQueue(IMqttServerOptions options, MqttClientSession clientSession, IMqttNetLogger logger) { _options = options ?? throw new ArgumentNullException(nameof(options)); _clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); }
MqttClientConnection CreateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter, MqttClientSession session, MqttConnectionValidatorContext connectionValidatorContext) { return(new MqttClientConnection( connectPacket, channelAdapter, session, connectionValidatorContext, _options, this, _retainedMessagesManager, _rootLogger)); }
public MqttEnqueuedApplicationMessage(MqttClientSession sender, MqttPublishPacket publishPacket) { Sender = sender; PublishPacket = publishPacket; }