/// <summary> /// Returns whether this message did acknowledge the specified sequence number. /// </summary> /// <param name="sequence"> /// The sequence number to check. /// </param> /// <returns> /// Whether this message acknowledges the specified sequence number. /// </returns> public bool DidAck(uint sequence) { if (!this.HasAck(sequence)) { return(false); } var diff = (MxUtility.UIntBitsize - MxUtility.GetSequenceNumberDifference(this.Ack, sequence)) - 1; return(((this.AckBitfield & (0x1u << (int)diff)) >> (int)diff) == 0x1); }
/// <summary> /// Handles the packets currently queued in the receive queue. /// </summary> private void PerformReceive() { if (this.m_ReceivedPackets.Count == 0) { this.m_DisconnectAccumulator++; return; } foreach (var packet in this.m_ReceivedPackets) { this.m_DisconnectAccumulator = 0; using (var memory = new MemoryStream(packet)) { var serializer = new MxMessageSerializer(); var message = (MxMessage)serializer.Deserialize(memory, null, typeof(MxMessage)); if (message.Payloads == null) { message.Payloads = new MxPayload[0]; } foreach (var payload in message.Payloads.Where(payload => payload.Data == null)) { payload.Data = new byte[0]; } var difference = MxUtility.GetSequenceNumberDifference( message.Sequence, this.m_RemoteSequenceNumber); if (difference > 0) { // Calculate the difference between the old // sequence number and the new sequence number // we need to push "false" into the queue for // the missing messages. for (var i = 0; i < difference - 1; i++) { this.PushIntoQueue(this.m_ReceiveQueue, false); } // We push the "true" value for this message after // firing the OnReceived event (so we can not acknowledge // it if the event callbacks do not want us to). // Check based on items in the queue. foreach (var kv in this.m_SendQueue.ToArray()) { var idx = kv.Key; if (!message.HasAck(idx)) { // We aren't acking this message yet. continue; } if (message.DidAck(idx)) { // We already checked for existance of the key above. var sendTimestamp = this.m_SendQueue[idx]; var rtt = this.GetUnixTimestamp() - sendTimestamp; this.PushIntoQueue(this.m_RTTQueue, rtt); var payloads = this.m_SendMessageQueue[idx]; this.m_SendQueue.Remove(idx); this.m_SendMessageQueue.Remove(idx); this.Latency = rtt; foreach (var payload in payloads.Value) { this.OnMessageAcknowledged( new MxMessageEventArgs { Client = this, Payload = payload, ProtocolID = payloads.Key }); } } else { this.HandleLostMessage(idx); } } foreach (var kv in this.m_SendQueue.ToArray()) { var idx = kv.Key; if (MxUtility.GetSequenceNumberDifference(message.Ack - MxUtility.UIntBitsize, idx) > 0) { this.HandleLostMessage(idx); } } this.m_RemoteSequenceNumber = message.Sequence; var doNotAcknowledge = false; foreach (var payload in message.Payloads) { var eventArgs = new MxMessageReceiveEventArgs { Client = this, Payload = payload.Data, DoNotAcknowledge = doNotAcknowledge, ProtocolID = message.ProtocolID }; this.OnMessageReceived(eventArgs); doNotAcknowledge = eventArgs.DoNotAcknowledge; } if (!doNotAcknowledge) { this.PushIntoQueue(this.m_ReceiveQueue, true); } } } } this.m_ReceivedPackets.Clear(); }
/// <summary> /// Returns whether or not this message can acknowledge the specified sequence number. /// This will return false if the specified sequence number is more than 32 messages ago. /// </summary> /// <param name="sequence"> /// The sequence number to check. /// </param> /// <returns> /// Whether this message can acknowledge the specified sequence number. /// </returns> public bool HasAck(uint sequence) { return(MxUtility.GetSequenceNumberDifference(this.Ack, sequence) >= 0 && MxUtility.GetSequenceNumberDifference(this.Ack, sequence) < MxUtility.UIntBitsize); }