/// <summary> /// Constructor /// </summary> public MqttSubscription() { this.ClientId = null; this.Topic = null; this.QosLevel = 0; this.ClientConnection = null; }
public static void Pubcomp(MqttClientConnection clientConnection, ushort messageId) { MqttMsgPubcomp pubcomp = new MqttMsgPubcomp(); pubcomp.MessageId = messageId; Send(clientConnection, pubcomp); }
/// <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(); }
/// <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; }
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); }
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); } } }
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; }
public static void Pubrel(MqttClientConnection clientConnection, ushort messageId, bool duplicate) { MqttMsgPubrel pubrel = new MqttMsgPubrel(); pubrel.MessageId = messageId; pubrel.DupFlag = duplicate; Send(clientConnection, pubrel); }
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); }
public static void Suback(MqttClientConnection clientConnection, ushort messageId, byte[] grantedQosLevels) { MqttMsgSuback suback = new MqttMsgSuback(); suback.MessageId = messageId; suback.GrantedQoSLevels = grantedQosLevels; Send(clientConnection, suback); }
public static void Send(MqttClientConnection clientConnection, byte[] msgBytes) { try { MqttAsyncTcpSender.Send(clientConnection.ReceiveSocketAsyncEventArgs.AcceptSocket, msgBytes); } catch (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); } }
/// <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); } }
public bool AuthenticateSubscriber(MqttClientConnection clientConnection, string topic) { if (SubscribeAuthentication == null) { return(true); } else { return(SubscribeAuthentication(clientConnection, topic)); } }
/// <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); } }
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); }
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); }