Beispiel #1
0
 /// <summary>
 /// Constructor
 /// </summary>
 public MqttSubscription()
 {
     this.ClientId         = null;
     this.Topic            = null;
     this.QosLevel         = 0;
     this.ClientConnection = null;
 }
Beispiel #2
0
        public static void Pubcomp(MqttClientConnection clientConnection, ushort messageId)
        {
            MqttMsgPubcomp pubcomp = new MqttMsgPubcomp();

            pubcomp.MessageId = messageId;
            Send(clientConnection, pubcomp);
        }
Beispiel #3
0
        /// <summary>
        /// Thread for handling keep alive message
        /// </summary>
        private void KeepAliveThread(MqttClientConnection clientConnection)
        {
            int delta = 0;
            int wait  = clientConnection.KeepAlivePeriod;

            // create event to signal that current thread is end
            clientConnection.KeepAliveEventEnd = new AutoResetEvent(false);

            while (clientConnection.IsRunning)
            {
                // waiting...
                clientConnection.KeepAliveEvent.WaitOne(wait);

                if (clientConnection.IsRunning)
                {
                    delta = Environment.TickCount - clientConnection.LastCommunicationTime;

                    // if timeout exceeded ...
                    if (delta >= clientConnection.KeepAlivePeriod)
                    {
                        // client must close connection
                        clientConnection.OnConnectionClosing();
                    }
                    else
                    {
                        // update waiting time
                        wait = clientConnection.KeepAlivePeriod - delta;
                    }
                }
            }

            // signal thread end
            clientConnection.KeepAliveEventEnd.Set();
        }
Beispiel #4
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="clientId">Client Id of the subscription</param>
 /// <param name="topic">Topic of subscription</param>
 /// <param name="qosLevel">QoS level of subscription</param>
 /// <param name="clientConnection">Client related to the subscription</param>
 public MqttSubscription(string clientId, string topic, byte qosLevel, MqttClientConnection clientConnection = null)
 {
     this.ClientId         = clientId;
     this.Topic            = topic;
     this.QosLevel         = qosLevel;
     this.ClientConnection = clientConnection;
 }
Beispiel #5
0
        public static void Puback(MqttClientConnection clientConnection, ushort messageId)
        {
            MqttMsgPuback puback = new MqttMsgPuback();

            puback.MessageId = messageId;
            Send(clientConnection, puback);
        }
 /// <summary>
 /// Raise client connected event
 /// </summary>
 /// <param name="e">Event args</param>
 private void OnClientConnected(MqttClientConnection clientConnection)
 {
     if (this.ClientConnected != null)
     {
         this.ClientConnected(this, new MqttClientConnectedEventArgs(clientConnection));
     }
 }
        private static int SendPubrel(MqttClientConnection clientConnection, MqttMsgContext msgContext, MqttMsgBase msgInflight, int timeout)
        {
            // QoS 2, PUBREL message to send to broker, state change to wait PUBCOMP
            if (msgContext.Flow == MqttMsgFlow.ToPublish)
            {
                msgContext.State     = MqttMsgState.WaitForPubcomp;
                msgContext.Timestamp = Environment.TickCount;
                msgContext.Attempt++;
                // retry ? set dup flag [v3.1.1] no needed
                if (clientConnection.ProtocolVersion == MqttProtocolVersion.Version_3_1 && msgContext.Attempt > 1)
                {
                    MqttOutgoingMessageManager.Pubrel(clientConnection, msgInflight.MessageId, true);
                }
                else
                {
                    MqttOutgoingMessageManager.Pubrel(clientConnection, msgInflight.MessageId, false);
                }

                // update timeout : minimum between delay (based on current message sent) or current timeout
                timeout = (clientConnection.Settings.DelayOnRetry < timeout) ? clientConnection.Settings.DelayOnRetry : timeout;

                // re-enqueue message
                clientConnection.EnqueueInflight(msgContext);
            }

            return(timeout);
        }
Beispiel #8
0
        public static void Pubrec(MqttClientConnection clientConnection, ushort messageId)
        {
            MqttMsgPubrec pubrec = new MqttMsgPubrec();

            pubrec.MessageId = messageId;
            Send(clientConnection, pubrec);
        }
        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);
                }
            }
        }
Beispiel #10
0
        private static void UnsubscribeFromTopicWithWildcard(string topic, MqttClientConnection clientConnection)
        {
            string topicReplaced = topic.Replace(PLUS_WILDCARD, PLUS_WILDCARD_REPLACE).Replace(SHARP_WILDCARD, SHARP_WILDCARD_REPLACE);

            List <MqttSubscription> subscriptionsForTopic;

            if (WildcardSubscriptions.TryGetValue(topicReplaced, out subscriptionsForTopic))
            {
                lock (subscriptionsForTopic)
                {
                    foreach (var subscription in subscriptionsForTopic)
                    {
                        if (subscription.ClientId == clientConnection.ClientId)
                        {
                            subscriptionsForTopic.Remove(subscription);
                            // TODO deal with topic with no subscribers

                            MqttSubscription subscriptionToBeRemoved;
                            clientConnection.Subscriptions.TryRemove(topicReplaced, out subscriptionToBeRemoved);
                            return;
                        }
                    }
                }
            }
        }
        private void CloseClientConnection(MqttClientConnection clientConnection)
        {
            // stop receiving thread
            clientConnection.IsRunning = false;

            clientConnection.IsConnected = false;
        }
Beispiel #12
0
        public static void Pubrel(MqttClientConnection clientConnection, ushort messageId, bool duplicate)
        {
            MqttMsgPubrel pubrel = new MqttMsgPubrel();

            pubrel.MessageId = messageId;
            pubrel.DupFlag   = duplicate;
            Send(clientConnection, pubrel);
        }
Beispiel #13
0
        public static void Unsuback(MqttClientConnection clientConnection, ushort messageId)
        {
            MqttMsgUnsuback unsuback = new MqttMsgUnsuback();

            unsuback.MessageId = messageId;

            Send(clientConnection, unsuback);
        }
 public void OpenClientConnection(MqttClientConnection clientConnection)
 {
     numberOfAssignedClients++;
     clientConnection.IsRunning         = true;
     clientConnection.ProcessingManager = this;
     asyncTcpReceiver.StartReceive(clientConnection.ReceiveSocketAsyncEventArgs);
     Task.Factory.StartNew(() => CheckForClientTimeout(clientConnection));
 }
        private static MqttMsgBase WaitForPubrel(MqttClientConnection clientConnection, MqttMsgContext msgContext, MqttMsgBase msgInflight, ref bool msgReceivedProcessed)
        {
            // QoS 2, waiting for PUBREL of a PUBREC message sent
            if (msgContext.Flow != MqttMsgFlow.ToAcknowledge)
            {
                return(null);
            }

            MqttMsgBase msgReceived;

            if (!clientConnection.InternalQueue.TryPeek(out msgReceived))
            {
                return(null);
            }

            InternalEvent internalEvent;

            // it is a PUBREL message
            if ((msgReceived != null) && (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREL_TYPE))
            {
                // PUBREL message for the current message, send PUBCOMP
                if (msgReceived.MessageId == msgInflight.MessageId)
                {
                    // received message processed
                    MqttMsgBase dequeuedMsg;
                    clientConnection.InternalQueue.TryDequeue(out dequeuedMsg);
                    msgReceivedProcessed = true;


                    MqttOutgoingMessageManager.Pubcomp(clientConnection, msgInflight.MessageId);


                    internalEvent = new MsgInternalEvent(msgInflight);
                    // notify published message from broker and acknowledged
                    clientConnection.EnqueueInternalEvent(internalEvent);

                    // PUBREL received (and PUBCOMP sent) for PUBLISH message with QoS Level 2, remove from session state
                    if ((msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) && (clientConnection.Session != null) &&
                        (clientConnection.Session.InflightMessages.ContainsKey(msgContext.Key)))
                    {
                        MqttMsgContext contextToBeRemoved;
                        clientConnection.Session.InflightMessages.TryRemove(msgContext.Key, out contextToBeRemoved);
                    }
                }
                else
                {
                    // re-enqueue message
                    clientConnection.EnqueueInflight(msgContext);
                }
            }
            else
            {
                // re-enqueue message
                clientConnection.EnqueueInflight(msgContext);
            }

            return(msgReceived);
        }
Beispiel #16
0
        public static void Suback(MqttClientConnection clientConnection, ushort messageId, byte[] grantedQosLevels)
        {
            MqttMsgSuback suback = new MqttMsgSuback();

            suback.MessageId        = messageId;
            suback.GrantedQoSLevels = grantedQosLevels;

            Send(clientConnection, suback);
        }
Beispiel #17
0
 public static void Send(MqttClientConnection clientConnection, byte[] msgBytes)
 {
     try
     {
         MqttAsyncTcpSender.Send(clientConnection.ReceiveSocketAsyncEventArgs.AcceptSocket, msgBytes);
     }
     catch (Exception)
     {
     }
 }
Beispiel #18
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);
            }
        }
Beispiel #19
0
 /// <summary>
 /// Remove a subscriber for a topic
 /// </summary>
 /// <param name="topic">Topic for unsubscription</param>
 /// <param name="clientConnection">Client to unsubscribe</param>
 public static void Unsubscribe(string topic, MqttClientConnection clientConnection)
 {
     if (IsWildcardSubscription(topic))
     {
         UnsubscribeFromTopicWithWildcard(topic, clientConnection);
     }
     else
     {
         UnsubscribeFromTopicWithoutWildcard(topic, clientConnection);
     }
 }
Beispiel #20
0
 public bool AuthenticateSubscriber(MqttClientConnection clientConnection, string topic)
 {
     if (SubscribeAuthentication == null)
     {
         return(true);
     }
     else
     {
         return(SubscribeAuthentication(clientConnection, topic));
     }
 }
Beispiel #21
0
 /// <summary>
 /// Add a subscriber for a topic
 /// </summary>
 /// <param name="topic">Topic for subscription</param>
 /// <param name="qosLevel">QoS level for the topic subscription</param>
 /// <param name="clientConnection">Client to subscribe</param>
 public static void Subscribe(string topic, byte qosLevel, MqttClientConnection clientConnection)
 {
     if (IsWildcardSubscription(topic))
     {
         SubscribeWithWildcard(topic, qosLevel, clientConnection);
     }
     else
     {
         SubscribeWithoutWildcard(topic, qosLevel, clientConnection);
     }
 }
Beispiel #22
0
 public bool AuthenticatePublish(MqttClientConnection clientConnection, string topic)
 {
     if (PublishAuthentication == null)
     {
         return(true);
     }
     else
     {
         return(PublishAuthentication(clientConnection, topic));
     }
 }
        private static int HandleQueuedQos1SendSubscribeAndSendUnsubscribe(
            MqttClientConnection clientConnection,
            MqttMsgContext msgContext,
            MqttMsgBase msgInflight,
            int timeout)
        {
            InternalEvent internalEvent;

            // QoS 1, PUBLISH or SUBSCRIBE/UNSUBSCRIBE message to send to broker, state change to wait PUBACK or SUBACK/UNSUBACK
            if (msgContext.Flow == MqttMsgFlow.ToPublish)
            {
                msgContext.Timestamp = Environment.TickCount;
                msgContext.Attempt++;

                if (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE)
                {
                    // PUBLISH message to send, wait for PUBACK
                    msgContext.State = MqttMsgState.WaitForPuback;
                    // retry ? set dup flag [v3.1.1] only for PUBLISH message
                    if (msgContext.Attempt > 1)
                    {
                        msgInflight.DupFlag = true;
                    }
                }
                else if (msgInflight.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE)
                {
                    // SUBSCRIBE message to send, wait for SUBACK
                    msgContext.State = MqttMsgState.WaitForSuback;
                }
                else if (msgInflight.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE)
                {
                    // UNSUBSCRIBE message to send, wait for UNSUBACK
                    msgContext.State = MqttMsgState.WaitForUnsuback;
                }

                MqttOutgoingMessageManager.Send(clientConnection, msgInflight);

                // update timeout : minimum between delay (based on current message sent) or current timeout
                timeout = (clientConnection.Settings.DelayOnRetry < timeout) ? clientConnection.Settings.DelayOnRetry : timeout;

                // re-enqueue message (I have to re-analyze for receiving PUBACK, SUBACK or UNSUBACK)
                clientConnection.EnqueueInflight(msgContext);
            }
            // QoS 1, PUBLISH message received from broker to acknowledge, send PUBACK
            else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge)
            {
                MqttOutgoingMessageManager.Puback(clientConnection, msgInflight.MessageId);

                internalEvent = new MsgInternalEvent(msgInflight);
                // notify published message from broker and acknowledged
                clientConnection.EnqueueInternalEvent(internalEvent);
            }
            return(timeout);
        }
        private static void OnMqttMsgUnsubscribeReceived(MqttClientConnection clientConnection, ushort messageId, string[] topics)
        {
            for (int i = 0; i < topics.Length; i++)
            {
                // unsubscribe client for each topic requested
                MqttSubscriberManager.Unsubscribe(topics[i], clientConnection);
            }

            // send UNSUBACK message to the client
            MqttOutgoingMessageManager.Unsuback(clientConnection, messageId);
        }
        /// <summary>
        /// Publish a message asynchronously
        /// </summary>
        /// <param name="topic">Message topic</param>
        /// <param name="message">Message data (payload)</param>
        /// <param name="qosLevel">QoS Level</param>
        /// <param name="retain">Retain flag</param>
        /// <returns>Message Id related to PUBLISH message</returns>
        public static ushort Publish(MqttClientConnection clientConnection, string topic, byte[] message, byte qosLevel, bool retain)
        {
            MqttMsgPublish publish = new MqttMsgPublish(topic, message, false, qosLevel, retain);

            publish.MessageId = clientConnection.GetMessageId();

            // enqueue message to publish into the inflight queue
            EnqueueInflight(clientConnection, publish, MqttMsgFlow.ToPublish);

            return(publish.MessageId);
        }
        private async void CheckForClientTimeout(MqttClientConnection clientConnection)
        {
            await Task.Delay(clientConnection.Settings.TimeoutOnConnection);

            // broker need to receive the first message (CONNECT)
            // within a reasonable amount of time after TCP/IP connection
            // wait on receiving message from client with a connection timeout
            if (clientConnection.IsRunning && !clientConnection.IsConnected && clientConnection.EventQueue.IsEmpty)
            {
                clientConnection.OnConnectionClosed();
            }
        }
        public void OnMqttMsgPublishReceived(MqttClientConnection clientConnection, MqttMsgPublish msg)
        {
            if (uacManager.AuthenticatePublish(clientConnection, msg.Topic))
            {
                // create PUBLISH message to publish
                // [v3.1.1] DUP flag from an incoming PUBLISH message is not propagated to subscribers
                //          It should be set in the outgoing PUBLISH message based on transmission for each subscriber
                MqttMsgPublish publish = new MqttMsgPublish(msg.Topic, msg.Message, false, msg.QosLevel, msg.Retain);

                // publish message through publisher manager
                this.publishManager.Publish(publish);
            }
        }
        public MqttRawMessage GetRawMessageWithData(MqttClientConnection clientConnection, byte messageType, byte[] buffer, int bufferOffset, int payloadLength)
        {
            //MqttRawMessage rawMessage;
            //if (!rawMessageBuffer.TryPop(out rawMessage))
            //{
            //    rawMessage = new MqttRawMessage(individualMessageBufferSize);
            //}
            var rawMessage = new MqttRawMessage(payloadLength);

            rawMessage.ClientConnection = clientConnection;
            rawMessage.MessageType      = messageType;
            rawMessage.PayloadLength    = payloadLength;
            Buffer.BlockCopy(buffer, bufferOffset, rawMessage.PayloadBuffer, 0, payloadLength);

            return(rawMessage);
        }
Beispiel #29
0
        public static MqttSubscription GetSubscription(string topic, MqttClientConnection clientConnection)
        {
            MqttSubscription subscription;

            if (IsWildcardSubscription(topic))
            {
                var topicReplaced = topic.Replace(PLUS_WILDCARD, PLUS_WILDCARD_REPLACE).Replace(SHARP_WILDCARD, SHARP_WILDCARD_REPLACE);
                clientConnection.Subscriptions.TryGetValue(topicReplaced, out subscription);
            }
            else
            {
                clientConnection.Subscriptions.TryGetValue(topic, out subscription);
            }

            return(subscription);
        }
        public void ReturnConnection(MqttClientConnection clientConnection)
        {
            try
            {
                clientConnection.ResetSocket();
            }
            catch (Exception)
            {
            }

            clientConnection.Reset();

            Interlocked.Increment(ref numberOfConnectionsReturned);

            unconnectedClientPool.Push(clientConnection);
        }