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);
                }
            }
        }
Beispiel #3
0
        /// <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);
            }
        }