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); }
internal bool Find(object item) { MqttMsgContext msgCtx = (MqttMsgContext)item; return((msgCtx.Message.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) && (msgCtx.Message.MessageId == this.MessageId) && msgCtx.Flow == this.Flow); }
private int HandleQueuedQos1SendSubscribeAndSendUnsubscribe( MqttConnection connection, 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; } outgoingMessageHandler.Send(connection, msgInflight); // update timeout : minimum between delay (based on current message sent) or current timeout timeout = connection.Settings.DelayOnRetry < timeout ? connection.Settings.DelayOnRetry : timeout; // re-enqueue message (I have to re-analyze for receiving PUBACK, SUBACK or UNSUBACK) connection.EnqueueInflight(msgContext); } // QoS 1, PUBLISH message received from broker to acknowledge, send PUBACK else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge) { outgoingMessageHandler.Puback(connection, msgInflight.MessageId); internalEvent = new InternalEvent(msgInflight); // notify published message from broker and acknowledged connection.EnqueueInternalEvent(internalEvent); } return(timeout); }
private MqttMsgBase WaitForPubrel( MqttConnection connection, MqttMsgContext msgContext, MqttMsgBase msgInflight, ref bool msgReceivedProcessed) { // QoS 2, waiting for PUBREL of a PUBREC message sent if (msgContext.Flow != MqttMsgFlow.ToAcknowledge) { return(null); } if (!connection.InternalQueue.TryPeek(out MqttMsgBase msgReceived)) { return(null); } InternalEvent internalEvent; // it is a PUBREL message if (msgReceived != null && msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREL_TYPE) { if (msgReceived.MessageId == msgInflight.MessageId) { // received message processed connection.InternalQueue.TryDequeue(out MqttMsgBase dequeuedMsg); msgReceivedProcessed = true; outgoingMessageHandler.Pubcomp(connection, msgInflight.MessageId); internalEvent = new InternalEvent(msgInflight); // notify published message from broker and acknowledged connection.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 && connection.Session != null && connection.Session.InflightMessages.ContainsKey(msgContext.Key)) { connection.Session.InflightMessages.TryRemove( msgContext.Key, out MqttMsgContext contextToBeRemoved); } } else { // re-enqueue message connection.EnqueueInflight(msgContext); } } else { connection.EnqueueInflight(msgContext); } return(msgReceived); }
public void AddInflightMessage(MqttMsgBase packet) { MqttMsgContext context = new MqttMsgContext(); Del d = delegate() { return(packet.QosLevel == (byte)0x01 ? MqttMsgState.QueuedQos1 : MqttMsgState.QueuedQos2); }; MqttMsgState state = packet.QosLevel == (byte)0x00 ? MqttMsgState.QueuedQos0 : d(); context.State = state; context.Message = packet; session.InflightMessages.Add(packet.MessageId, context); }
public void EnqueueInflight(MqttMsgContext inflightMessageContext) { if (this.ConnectionManager != null) { this.InflightQueue.Enqueue(inflightMessageContext); this.ConnectionManager.EnqueueClientConnectionWithInflightQueueToProcess(new InflightQueueProcessEvent { Connection = this, IsCallback = false }); } }
private static void HandleQueuedQos0( MqttClientConnection clientConnection, MqttMsgContext msgContext, MqttMsgBase msgInflight) { // QoS 0, PUBLISH message to send to broker, no state change, no acknowledge if (msgContext.Flow == MqttMsgFlow.ToPublish) { MqttOutgoingMessageManager.Send(clientConnection, msgInflight); } // QoS 0, no need acknowledge else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge) { var internalEvent = new MsgInternalEvent(msgInflight); clientConnection.EnqueueInternalEvent(internalEvent); } }
private int HandleQueuedQos2( MqttConnection connection, MqttMsgContext msgContext, MqttMsgBase msgInflight, int timeout) { // QoS 2, PUBLISH message to send to broker, state change to wait PUBREC if (msgContext.Flow == MqttMsgFlow.ToPublish) { msgContext.Timestamp = Environment.TickCount; msgContext.Attempt++; msgContext.State = MqttMsgState.WaitForPubrec; // retry ? set dup flag if (msgContext.Attempt > 1) { msgInflight.DupFlag = true; } outgoingMessageHandler.Send(connection, msgInflight); // update timeout : minimum between delay (based on current message sent) or current timeout timeout = connection.Settings.DelayOnRetry < timeout ? connection.Settings.DelayOnRetry : timeout; // re-enqueue message (I have to re-analyze for receiving PUBREC) connection.EnqueueInflight(msgContext); } // QoS 2, PUBLISH message received from broker to acknowledge, send PUBREC, state change to wait PUBREL else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge) { msgContext.State = MqttMsgState.WaitForPubrel; outgoingMessageHandler.Pubrec(connection, msgInflight.MessageId); // re-enqueue message (I have to re-analyze for receiving PUBREL) connection.EnqueueInflight(msgContext); } return(timeout); }
private static MqttMsgBase HandleWaitForPubackSubackUbsuback( MqttClientConnection clientConnection, MqttMsgContext msgContext, MqttMsgBase msgInflight, ref bool msgReceivedProcessed, ref int timeout) { // QoS 1, waiting for PUBACK of a PUBLISH message sent or // waiting for SUBACK of a SUBSCRIBE message sent or // waiting for UNSUBACK of a UNSUBSCRIBE message sent or if (msgContext.Flow != MqttMsgFlow.ToPublish) { return(null); } MqttMsgBase msgReceived; if (!clientConnection.InternalQueue.TryPeek(out msgReceived)) { return(null); } bool acknowledge = false; InternalEvent internalEvent; // PUBACK message or SUBACK/UNSUBACK message for the current message if (((msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) && (msgReceived.MessageId == msgInflight.MessageId)) || ((msgReceived.Type == MqttMsgBase.MQTT_MSG_SUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE) && (msgReceived.MessageId == msgInflight.MessageId)) || ((msgReceived.Type == MqttMsgBase.MQTT_MSG_UNSUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE) && (msgReceived.MessageId == msgInflight.MessageId))) { // received message processed MqttMsgBase dequeuedMsg; clientConnection.InternalQueue.TryDequeue(out dequeuedMsg); acknowledge = true; msgReceivedProcessed = true; // if PUBACK received, confirm published with flag if (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBACK_TYPE) { internalEvent = new MsgPublishedInternalEvent(msgReceived, true); } else { internalEvent = new MsgInternalEvent(msgReceived); } // notify received acknowledge from broker of a published message or subscribe/unsubscribe message clientConnection.EnqueueInternalEvent(internalEvent); // PUBACK received for PUBLISH message with QoS Level 1, 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); } } // current message not acknowledged, no PUBACK or SUBACK/UNSUBACK or not equal messageid if (!acknowledge) { var delta = Environment.TickCount - msgContext.Timestamp; // check timeout for receiving PUBACK since PUBLISH was sent or // for receiving SUBACK since SUBSCRIBE was sent or // for receiving UNSUBACK since UNSUBSCRIBE was sent if (delta >= clientConnection.Settings.DelayOnRetry) { // max retry not reached, resend if (msgContext.Attempt < clientConnection.Settings.AttemptsOnRetry) { msgContext.State = MqttMsgState.QueuedQos1; // re-enqueue message clientConnection.EnqueueInflight(msgContext); // update timeout (0 -> reanalyze queue immediately) timeout = 0; } else { // if PUBACK for a PUBLISH message not received after retries, raise event for not published if (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) { // PUBACK not received in time, PUBLISH retries failed, need to remove from session inflight messages too if ((clientConnection.Session != null) && (clientConnection.Session.InflightMessages.ContainsKey(msgContext.Key))) { MqttMsgContext contextToBeRemoved; clientConnection.Session.InflightMessages.TryRemove(msgContext.Key, out contextToBeRemoved); } internalEvent = new MsgPublishedInternalEvent(msgInflight, false); // notify not received acknowledge from broker and message not published clientConnection.EnqueueInternalEvent(internalEvent); } // NOTE : not raise events for SUBACK or UNSUBACK not received // for the user no event raised means subscribe/unsubscribe failed } } else { // re-enqueue message (I have to re-analyze for receiving PUBACK, SUBACK or UNSUBACK) clientConnection.EnqueueInflight(msgContext); // update timeout int msgTimeout = (clientConnection.Settings.DelayOnRetry - delta); timeout = (msgTimeout < timeout) ? msgTimeout : timeout; } } return(msgReceived); }
private static MqttMsgBase HandleWaitForPubrec( MqttClientConnection clientConnection, MqttMsgContext msgContext, MqttMsgBase msgInflight, ref bool msgReceivedProcessed, ref int timeout) { // QoS 2, waiting for PUBREC of a PUBLISH message sent if (msgContext.Flow != MqttMsgFlow.ToPublish) { return(null); } MqttMsgBase msgReceived; if (!clientConnection.InternalQueue.TryPeek(out msgReceived)) { return(null); } bool acknowledge = false; InternalEvent internalEvent; // it is a PUBREC message if (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREC_TYPE) { // PUBREC message for the current PUBLISH message, send PUBREL, wait for PUBCOMP if (msgReceived.MessageId == msgInflight.MessageId) { // received message processed MqttMsgBase dequeuedMsg; clientConnection.InternalQueue.TryDequeue(out dequeuedMsg); acknowledge = true; msgReceivedProcessed = true; MqttOutgoingMessageManager.Pubrel(clientConnection, msgInflight.MessageId, false); msgContext.State = MqttMsgState.WaitForPubcomp; msgContext.Timestamp = Environment.TickCount; msgContext.Attempt = 1; // 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); } } // current message not acknowledged if (!acknowledge) { var delta = Environment.TickCount - msgContext.Timestamp; // check timeout for receiving PUBREC since PUBLISH was sent if (delta >= clientConnection.Settings.DelayOnRetry) { // max retry not reached, resend if (msgContext.Attempt < clientConnection.Settings.AttemptsOnRetry) { msgContext.State = MqttMsgState.QueuedQos2; // re-enqueue message clientConnection.EnqueueInflight(msgContext); // update timeout (0 -> reanalyze queue immediately) timeout = 0; } else { // PUBREC not received in time, PUBLISH retries failed, need to remove from session inflight messages too if ((clientConnection.Session != null) && (clientConnection.Session.InflightMessages.ContainsKey(msgContext.Key))) { MqttMsgContext contextToBeRemoved; clientConnection.Session.InflightMessages.TryRemove(msgContext.Key, out contextToBeRemoved); } // if PUBREC for a PUBLISH message not received after retries, raise event for not published internalEvent = new MsgPublishedInternalEvent(msgInflight, false); // notify not received acknowledge from broker and message not published clientConnection.EnqueueInternalEvent(internalEvent); } } else { // re-enqueue message clientConnection.EnqueueInflight(msgContext); // update timeout int msgTimeout = (clientConnection.Settings.DelayOnRetry - delta); timeout = (msgTimeout < timeout) ? msgTimeout : timeout; } } return(msgReceived); }
private static MqttMsgBase WaitForPubcomp( MqttClientConnection clientConnection, MqttMsgContext msgContext, MqttMsgBase msgInflight, ref bool msgReceivedProcessed, ref int timeout) { // QoS 2, waiting for PUBCOMP of a PUBREL message sent if (msgContext.Flow != MqttMsgFlow.ToPublish) { return(null); } MqttMsgBase msgReceived; if (!clientConnection.InternalQueue.TryPeek(out msgReceived)) { return(null); } bool acknowledge = false; InternalEvent internalEvent; // it is a PUBCOMP message if (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBCOMP_TYPE) { // PUBCOMP message for the current message if (msgReceived.MessageId == msgInflight.MessageId) { MqttMsgBase dequeuedMsg; clientConnection.InternalQueue.TryDequeue(out dequeuedMsg); acknowledge = true; msgReceivedProcessed = true; internalEvent = new MsgPublishedInternalEvent(msgReceived, true); // notify received acknowledge from broker of a published message clientConnection.EnqueueInternalEvent(internalEvent); // PUBCOMP received 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); } } } // it is a PUBREC message else if (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREC_TYPE) { // another PUBREC message for the current message due to a retransmitted PUBLISH // I'm in waiting for PUBCOMP, so I can discard clientConnection PUBREC if (msgReceived.MessageId == msgInflight.MessageId) { MqttMsgBase dequeuedMsg; clientConnection.InternalQueue.TryDequeue(out dequeuedMsg); acknowledge = true; msgReceivedProcessed = true; // re-enqueue message clientConnection.EnqueueInflight(msgContext); } } // current message not acknowledged if (!acknowledge) { var delta = Environment.TickCount - msgContext.Timestamp; // check timeout for receiving PUBCOMP since PUBREL was sent if (delta >= clientConnection.Settings.DelayOnRetry) { // max retry not reached, resend if (msgContext.Attempt < clientConnection.Settings.AttemptsOnRetry) { msgContext.State = MqttMsgState.SendPubrel; // re-enqueue message clientConnection.EnqueueInflight(msgContext); // update timeout (0 -> reanalyze queue immediately) timeout = 0; } else { // PUBCOMP not received, PUBREL retries failed, need to remove from session inflight messages too if ((clientConnection.Session != null) && clientConnection.Session.InflightMessages.ContainsKey(msgContext.Key)) { MqttMsgContext contextToBeRemoved; clientConnection.Session.InflightMessages.TryRemove(msgContext.Key, out contextToBeRemoved); } // if PUBCOMP for a PUBLISH message not received after retries, raise event for not published internalEvent = new MsgPublishedInternalEvent(msgInflight, false); // notify not received acknowledge from broker and message not published clientConnection.EnqueueInternalEvent(internalEvent); } } else { // re-enqueue message clientConnection.EnqueueInflight(msgContext); // update timeout int msgTimeout = clientConnection.Settings.DelayOnRetry - delta; timeout = (msgTimeout < timeout) ? msgTimeout : timeout; } } return(msgReceived); }
private void EnqueueInflight(MqttConnection connection, MqttMsgBase msg, MqttMsgFlow flow) { // enqueue is needed (or not) var enqueue = true; // if it is a PUBLISH message with QoS Level 2 if (msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE && msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE) { // if it is a PUBLISH message already received (it is in the inflight queue), the publisher // re-sent it because it didn't received the PUBREC. In connection case, we have to re-send PUBREC // NOTE : I need to find on message id and flow because the broker could be publish/received // to/from client and message id could be the same (one tracked by broker and the other by client) var msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToAcknowledge); var msgCtx = (MqttMsgContext)connection.InflightQueue.FirstOrDefault(msgCtxFinder.Find); // the PUBLISH message is alredy in the inflight queue, we don't need to re-enqueue but we need // to change state to re-send PUBREC if (msgCtx != null) { msgCtx.State = MqttMsgState.QueuedQos2; msgCtx.Flow = MqttMsgFlow.ToAcknowledge; enqueue = false; } } if (enqueue) { // set a default state var state = MqttMsgState.QueuedQos0; // based on QoS level, the messages flow between broker and client changes switch (msg.QosLevel) { // QoS Level 0 case MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE: state = MqttMsgState.QueuedQos0; break; // QoS Level 1 case MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE: state = MqttMsgState.QueuedQos1; break; // QoS Level 2 case MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE: state = MqttMsgState.QueuedQos2; break; } // [v3.1.1] SUBSCRIBE and UNSUBSCRIBE aren't "officially" QOS = 1 // so QueuedQos1 state isn't valid for them if (msg.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE) { state = MqttMsgState.SendSubscribe; } else if (msg.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE) { state = MqttMsgState.SendUnsubscribe; } // queue message context var msgContext = new MqttMsgContext() { Message = msg, State = state, Flow = flow, Attempt = 0 }; // enqueue message and unlock send thread connection.EnqueueInflight(msgContext); // PUBLISH message if (msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) { if (msgContext.Flow == MqttMsgFlow.ToPublish && (msg.QosLevel == MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE || msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE)) { if (connection.Session != null) { connection.Session.InflightMessages.TryAdd(msgContext.Key, msgContext); } } // to acknowledge and QoS level 2 else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge && msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE) { if (connection.Session != null) { connection.Session.InflightMessages.TryAdd(msgContext.Key, msgContext); } } } } }
private static void EnqueueInternal(MqttClientConnection clientConnection, MqttMsgBase msg) { // enqueue is needed (or not) bool enqueue = true; // if it is a PUBREL message (for QoS Level 2) if (msg.Type == MqttMsgBase.MQTT_MSG_PUBREL_TYPE) { // if it is a PUBREL but the corresponding PUBLISH isn't in the inflight queue, // it means that we processed PUBLISH message and received PUBREL and we sent PUBCOMP // but publisher didn't receive PUBCOMP so it re-sent PUBREL. We need only to re-send PUBCOMP. // NOTE : I need to find on message id and flow because the broker could be publish/received // to/from client and message id could be the same (one tracked by broker and the other by client) MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToAcknowledge); MqttMsgContext msgCtx = (MqttMsgContext)clientConnection.InflightQueue.FirstOrDefault(msgCtxFinder.Find); // the PUBLISH message isn't in the inflight queue, it was already processed so // we need to re-send PUBCOMP only if (msgCtx == null) { MqttOutgoingMessageManager.Pubcomp(clientConnection, msg.MessageId); enqueue = false; } } // if it is a PUBCOMP message (for QoS Level 2) else if (msg.Type == MqttMsgBase.MQTT_MSG_PUBCOMP_TYPE) { // if it is a PUBCOMP but the corresponding PUBLISH isn't in the inflight queue, // it means that we sent PUBLISH message, sent PUBREL (after receiving PUBREC) and already received PUBCOMP // but publisher didn't receive PUBREL so it re-sent PUBCOMP. We need only to ignore clientConnection PUBCOMP. // NOTE : I need to find on message id and flow because the broker could be publish/received // to/from client and message id could be the same (one tracked by broker and the other by client) MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToPublish); MqttMsgContext msgCtx = (MqttMsgContext)clientConnection.InflightQueue.FirstOrDefault(msgCtxFinder.Find); // the PUBLISH message isn't in the inflight queue, it was already sent so we need to ignore clientConnection PUBCOMP if (msgCtx == null) { enqueue = false; } } // if it is a PUBREC message (for QoS Level 2) else if (msg.Type == MqttMsgBase.MQTT_MSG_PUBREC_TYPE) { // if it is a PUBREC but the corresponding PUBLISH isn't in the inflight queue, // it means that we sent PUBLISH message more times (retries) but broker didn't send PUBREC in time // the publish is failed and we need only to ignore rawMessage.ClientConnection PUBREC. // NOTE : I need to find on message id and flow because the broker could be publish/received // to/from client and message id could be the same (one tracked by broker and the other by client) MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToPublish); MqttMsgContext msgCtx = (MqttMsgContext)clientConnection.InflightQueue.FirstOrDefault(msgCtxFinder.Find); // the PUBLISH message isn't in the inflight queue, it was already sent so we need to ignore rawMessage.ClientConnection PUBREC if (msgCtx == null) { enqueue = false; } } if (enqueue) { clientConnection.InternalQueue.Enqueue(msg); } }