public void OnMqttMsgSubscribeReceived(MqttClientConnection clientConnection, ushort messageId, string[] topics, byte[] qosLevels) { var wasSubscribed = false; for (var i = 0; i < topics.Length; i++) { if (uacManager.AuthenticateSubscriber(clientConnection, topics[i])) { // TODO : business logic to grant QoS levels based on some conditions ? // now the broker granted the QoS levels requested by client // subscribe client for each topic and QoS level requested MqttSubscriberManager.Subscribe(topics[i], qosLevels[i], clientConnection); wasSubscribed = true; } } if (wasSubscribed) { // send SUBACK message to the client MqttOutgoingMessageManager.Suback(clientConnection, messageId, qosLevels); foreach (var topic in topics) { // publish retained message on the current subscription RetainedMessageManager.PublishRetaind(topic, clientConnection); } } }
private void PublishThread() { while (this.isRunning) { try { var publish = (MqttMsgPublish)this.publishQueue.Take(); if (publish != null) { Interlocked.Increment(ref numberOfMessagesPublished); // get all subscriptions for a topic var subscriptions = MqttSubscriberManager.GetSubscriptionsByTopic(publish.Topic); foreach (var subscription in subscriptions) { var qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel; // send PUBLISH message to the current subscriber MqttMessageToClientConnectionManager.Publish(subscription.ClientConnection, publish.Topic, publish.Message, qosLevel, publish.Retain); } } } catch (Exception exception) { logger.LogException(this, exception); } } }
/// <summary> /// Publish retained message for a topic to a client /// </summary> /// <param name="topic">Topic to search for a retained message</param> /// <param name="clientId">Client Id to send retained message</param> public static void PublishRetaind(string topic, MqttClientConnection clientConnection) { MqttSubscription subscription = MqttSubscriberManager.GetSubscription(topic, clientConnection); // add subscription to list of subscribers for receiving retained messages if (subscription != null) { SubscribersForRetained.Add(subscription); } }
public void OnConnectionClosed(MqttClientConnection clientConnection) { // if client is connected MqttClientConnection connectedClient; if (clientConnection.IsConnected && MqttBroker.TryRemoveClientConnection(clientConnection.ClientId, out connectedClient)) { // client has a will message if (clientConnection.WillFlag) { // create the will PUBLISH message MqttMsgPublish publish = new MqttMsgPublish(clientConnection.WillTopic, Encoding.UTF8.GetBytes(clientConnection.WillMessage), false, clientConnection.WillQosLevel, false); // publish message through publisher manager this.publishManager.Publish(publish); } // if not clean session if (!clientConnection.CleanSession) { List <MqttSubscription> subscriptions = clientConnection.Subscriptions.Values.ToList(); if (subscriptions.Count > 0) { MqttSessionManager.SaveSession(clientConnection.ClientId, clientConnection.Session, subscriptions); // TODO : persist client session if broker close } } foreach (var topic in clientConnection.Subscriptions.Keys) { // delete client from runtime subscription MqttSubscriberManager.Unsubscribe(topic, clientConnection); } // close the client CloseClientConnection(clientConnection); clientConnectionManager.ReturnConnection(clientConnection); Interlocked.Decrement(ref numberOfConnectedClients); } }
public void OnMqttMsgConnected(MqttClientConnection clientConnection, MqttMsgConnect message) { clientConnection.ProtocolVersion = (MqttProtocolVersion)message.ProtocolVersion; // verify message to determine CONNACK message return code to the client byte returnCode = MqttConnectVerify(message); // [v3.1.1] if client id is zero length, the broker assigns a unique identifier to it var clientId = (message.ClientId.Length != 0) ? message.ClientId : Guid.NewGuid().ToString(); // connection "could" be accepted if (returnCode == MqttMsgConnack.CONN_ACCEPTED) { // check if there is a client already connected with same client Id MqttClientConnection clientConnectionConnected = MqttBroker.GetClientConnection(clientId); // force connection close to the existing client (MQTT protocol) if (clientConnectionConnected != null) { OnConnectionClosed(clientConnectionConnected); } // add client to the collection MqttBroker.TryAddClientConnection(clientId, clientConnection); Interlocked.Increment(ref numberOfConnectedClients); } // connection accepted, load (if exists) client session if (returnCode == MqttMsgConnack.CONN_ACCEPTED) { // check if not clean session and try to recovery a session if (!message.CleanSession) { // create session for the client MqttClientSession clientSession = new MqttClientSession(clientId); // get session for the connected client MqttBrokerSession session = MqttSessionManager.GetSession(clientId); // [v3.1.1] session present flag bool sessionPresent = false; // set inflight queue into the client session if (session != null) { clientSession.InflightMessages = session.InflightMessages; // [v3.1.1] session present flag if (clientConnection.ProtocolVersion == MqttProtocolVersion.Version_3_1_1) { sessionPresent = true; } } // send CONNACK message to the client MqttOutgoingMessageManager.Connack(clientConnection, message, returnCode, clientId, sessionPresent); // load/inject session to the client clientConnection.LoadSession(clientSession); if (session != null) { // set reference to connected client into the session session.ClientConnection = clientConnection; // there are saved subscriptions if (session.Subscriptions != null) { // register all subscriptions for the connected client foreach (MqttSubscription subscription in session.Subscriptions) { MqttSubscriberManager.Subscribe( subscription.Topic, subscription.QosLevel, clientConnection); // publish retained message on the current subscription RetainedMessageManager.PublishRetaind(subscription.Topic, clientConnection); } } // there are saved outgoing messages if (session.OutgoingMessages.Count > 0) { // publish outgoing messages for the session this.publishManager.PublishSession(session.ClientId); } } } // requested clean session else { // send CONNACK message to the client MqttOutgoingMessageManager.Connack(clientConnection, message, returnCode, clientId, false); MqttSessionManager.ClearSession(clientId); } } else { // send CONNACK message to the client MqttOutgoingMessageManager.Connack(clientConnection, message, returnCode, clientId, false); } }