コード例 #1
0
        private void ClientsForSessionThread()
        {
            while (isRunning)
            {
                try
                {
                    string clientId = this.clientsForSession.Take();

                    MqttBrokerSession session = MqttSessionManager.GetSession(clientId);

                    MqttMsgPublish outgoingMsg;
                    while (session.OutgoingMessages.TryDequeue(out outgoingMsg))
                    {
                        var query = from s in session.Subscriptions
                                    where (new Regex(s.Topic)).IsMatch(outgoingMsg.Topic)
                                    // check for topics based also on wildcard with regex
                                    select s;

                        MqttSubscription subscription = query.FirstOrDefault();

                        if (subscription != null)
                        {
                            var qosLevel = (subscription.QosLevel < outgoingMsg.QosLevel) ? subscription.QosLevel : outgoingMsg.QosLevel;
                            MqttMessageToClientConnectionManager.Publish(subscription.ClientConnection, outgoingMsg.Topic, outgoingMsg.Message, qosLevel, outgoingMsg.Retain);
                        }
                    }
                }
                catch (Exception exception)
                {
                    logger.LogException(this, exception);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Save session for a client (all related subscriptions)
        /// </summary>
        /// <param name="clientId">Client Id to save subscriptions</param>
        /// <param name="clientSession">Client session with inflight messages</param>
        /// <param name="subscriptions">Subscriptions to save</param>
        public void SaveSession(string clientId, MqttClientSession clientSession, List <MqttSubscription> subscriptions)
        {
            MqttBrokerSession session = null;

            lock (this.sessions)
            {
                // session doesn't exist
                if (!this.sessions.ContainsKey(clientId))
                {
                    // create new session
                    session          = new MqttBrokerSession();
                    session.ClientId = clientId;

                    // add to sessions list
                    this.sessions.Add(clientId, session);
                }
                else
                {
                    // get existing session
                    session = this.sessions[clientId];
                }
            }

            // null reference to disconnected client
            session.Client = null;

            // update subscriptions
            session.Subscriptions = new List <MqttSubscription>();
            lock (session.Subscriptions)
            {
                foreach (MqttSubscription subscription in subscriptions)
                {
                    session.Subscriptions.Add(new MqttSubscription(subscription.ClientId, subscription.Topic, subscription.QosLevel, null));
                }
            }

            // update inflight messages
            session.InflightMessages = new Hashtable();
            lock (session.InflightMessages)
            {
                foreach (MqttMsgContext msgContext in clientSession.InflightMessages.Values)
                {
                    session.InflightMessages.Add(msgContext.Key, msgContext);
                }
            }
        }
コード例 #3
0
ファイル: MqttBroker.cs プロジェクト: OOP-03376400/iotDash
        void Client_MqttMsgConnected(object sender, MqttMsgConnectEventArgs e)
        {
            // [v3.1.1] session present flag
            bool sessionPresent = false;
            // [v3.1.1] generated client id for client who provides client id zero bytes length
            string clientId = null;

            MqttClient client = (MqttClient)sender;

            // verify message to determine CONNACK message return code to the client
            byte returnCode = this.MqttConnectVerify(e.Message);

            // [v3.1.1] if client id is zero length, the broker assigns a unique identifier to it
            clientId = (e.Message.ClientId.Length != 0) ? e.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
                MqttClient clientConnected = this.GetClient(clientId);

                // force connection close to the existing client (MQTT protocol)
                if (clientConnected != null)
                {
                    this.CloseClient(clientConnected);
                }
            }

            try
            {
                // connection accepted, load (if exists) client session
                if (returnCode == MqttMsgConnack.CONN_ACCEPTED)
                {
                    // check if not clean session and try to recovery a session
                    if (!e.Message.CleanSession)
                    {
                        // create session for the client
                        MqttClientSession clientSession = new MqttClientSession(clientId);

                        // get session for the connected client
                        MqttBrokerSession session = this.sessionManager.GetSession(clientId);

                        // set inflight queue into the client session
                        if (session != null)
                        {
                            clientSession.InflightMessages = session.InflightMessages;
                            // [v3.1.1] session present flag
                            if (client.ProtocolVersion == MqttProtocolVersion.Version_3_1_1)
                            {
                                sessionPresent = true;
                            }
                        }

                        // send CONNACK message to the client
                        client.Connack(e.Message, returnCode, clientId, sessionPresent);

                        // load/inject session to the client
                        client.LoadSession(clientSession);

                        if (session != null)
                        {
                            // set reference to connected client into the session
                            session.Client = client;

                            // there are saved subscriptions
                            if (session.Subscriptions != null)
                            {
                                // register all subscriptions for the connected client
                                foreach (MqttSubscription subscription in session.Subscriptions)
                                {
                                    this.subscriberManager.Subscribe(subscription.Topic, subscription.QosLevel, client);

                                    // publish retained message on the current subscription
                                    this.publisherManager.PublishRetaind(subscription.Topic, clientId);
                                }
                            }

                            // there are saved outgoing messages
                            if (session.OutgoingMessages.Count > 0)
                            {
                                // publish outgoing messages for the session
                                this.publisherManager.PublishSession(session.ClientId);
                            }
                        }

                        //signal
                        EventHandler <MqttClientEventArgs> handler = DidAcceptNewClient;
                        if (handler != null)
                        {
                            MqttClientEventArgs arg = new MqttClientEventArgs();
                            arg.Client = client;
                            handler(this, arg);
                        }
                    }
                    // requested clean session
                    else
                    {
                        // send CONNACK message to the client
                        client.Connack(e.Message, returnCode, clientId, sessionPresent);

                        this.sessionManager.ClearSession(clientId);
                    }
                }
                else
                {
                    // send CONNACK message to the client
                    client.Connack(e.Message, returnCode, clientId, sessionPresent);
                }
            }
            catch (MqttCommunicationException)
            {
                this.CloseClient(client);
            }
        }
コード例 #4
0
        /// <summary>
        /// Process the message queue to publish
        /// </summary>
        public void PublishThread()
        {
            int            count;
            byte           qosLevel;
            MqttMsgPublish publish;

            // create event to signal that current thread is ended
            this.publishEventEnd = new AutoResetEvent(false);

            while (this.isRunning)
            {
                // wait on message queueud to publish
                this.publishQueueWaitHandle.WaitOne();

                // first check new subscribers to send retained messages ...
                lock (this.subscribersForRetained)
                {
                    count = this.subscribersForRetained.Count;

                    // publish retained messages to subscribers (new or reconnected)
                    while (count > 0)
                    {
                        count--;
                        MqttSubscription subscription = this.subscribersForRetained.Dequeue();

                        var query = from p in this.retainedMessages
                                    where (new Regex(subscription.Topic)).IsMatch(p.Key)     // check for topics based also on wildcard with regex
                                    select p.Value;

                        if (query.Count() > 0)
                        {
                            // reverse loop to allow for changes in "this.retainedMessages"
                            for (int i = query.Count() - 1; i >= 0; i--)
                            {
                                MqttMsgPublish retained = query.ElementAt(i);

                                qosLevel = (subscription.QosLevel < retained.QosLevel) ? subscription.QosLevel : retained.QosLevel;

                                // send PUBLISH message to the current subscriber
                                subscription.Client.Publish(retained.Topic, retained.Message, qosLevel, retained.Retain);
                            }
                        }
                    }
                }

                // ... then check clients to send outgoing session messages
                lock (this.clientsForSession)
                {
                    count = this.clientsForSession.Count;

                    // publish outgoing session messages to clients (reconnected)
                    while (count > 0)
                    {
                        count--;
                        string clientId = this.clientsForSession.Dequeue();

                        MqttBrokerSession session = this.sessionManager.GetSession(clientId);

                        while (session.OutgoingMessages.Count > 0)
                        {
                            MqttMsgPublish outgoingMsg = session.OutgoingMessages.Dequeue();

                            var query = from s in session.Subscriptions
                                        where (new Regex(s.Topic)).IsMatch(outgoingMsg.Topic) // check for topics based also on wildcard with regex
                                        select s;

                            MqttSubscription subscription = query.First();

                            if (subscription != null)
                            {
                                qosLevel = (subscription.QosLevel < outgoingMsg.QosLevel) ? subscription.QosLevel : outgoingMsg.QosLevel;

                                session.Client.Publish(outgoingMsg.Topic, outgoingMsg.Message, qosLevel, outgoingMsg.Retain);
                            }
                        }
                    }
                }

                // ... then pass to process publish queue
                lock (this.publishQueue)
                {
                    publish = null;

                    count = this.publishQueue.Count;
                    // publish all queued messages
                    while (count > 0)
                    {
                        count--;
                        publish = (MqttMsgPublish)this.publishQueue.Dequeue();

                        if (publish != null)
                        {
                            // get all subscriptions for a topic
                            List <MqttSubscription> subscriptions = this.subscriberManager.GetSubscriptionsByTopic(publish.Topic);

                            if ((subscriptions != null) && (subscriptions.Count > 0))
                            {
                                foreach (MqttSubscription subscription in subscriptions)
                                {
                                    qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel;

                                    // send PUBLISH message to the current subscriber
                                    subscription.Client.Publish(publish.Topic, publish.Message, qosLevel, publish.Retain);
                                }
                            }

                            // get all sessions
                            List <MqttBrokerSession> sessions = this.sessionManager.GetSessions();

                            if ((sessions != null) && (sessions.Count > 0))
                            {
                                foreach (MqttBrokerSession session in sessions)
                                {
                                    var query = from s in session.Subscriptions
                                                where (new Regex(s.Topic)).IsMatch(publish.Topic)
                                                select s;

                                    MqttSubscriptionComparer comparer = new MqttSubscriptionComparer(MqttSubscriptionComparer.MqttSubscriptionComparerType.OnClientId);

                                    // consider only session active for client disconnected (not online)
                                    if (session.Client == null)
                                    {
                                        foreach (MqttSubscription subscription in query.Distinct(comparer))
                                        {
                                            qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel;

                                            // save PUBLISH message for client disconnected (not online)
                                            session.OutgoingMessages.Enqueue(publish);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // signal thread end
            this.publishEventEnd.Set();
        }
        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);
            }
        }