/// <summary> /// Raise the MessageReceived event. /// </summary> /// <param name="e"> /// The event arguments. /// </param> protected virtual void OnMessageReceived(MxMessageReceiveEventArgs e) { var handler = this.MessageReceived; if (handler != null) { handler(this, e); } }
/// <summary> /// Called when we have received a fragment from the underlying client. /// </summary> /// <param name="sender"> /// The sender. /// </param> /// <param name="mxMessageEventArgs"> /// The message event args. /// </param> private void ClientOnMessageReceived(object sender, MxMessageReceiveEventArgs mxMessageEventArgs) { if (mxMessageEventArgs.ProtocolID != MxMessage.ReliableProtocol) { return; } var data = mxMessageEventArgs.Payload; // Format of a packet is: // Byte 0 - 3: message ID // Byte 4 - 5: length // Byte 6: current index // Byte 7: total packets // Remaining bytes are the fragment data var messageID = BitConverter.ToInt32(data, 0); var length = BitConverter.ToUInt16(data, 4); var currentIndex = (int)data[6]; var totalPackets = (int)data[7]; if (!this.m_ActiveReceiveMessages.ContainsKey(messageID)) { // Add a new entry in the active receive messages dictionary. this.m_ActiveReceiveMessages.Add( messageID, new MxReliabilityReceiveState(messageID, totalPackets)); } // Check for invalid payload. if ((length - 1) + DataOffset >= data.Length) { var errorMessage = "The payload data received had an invalid length for the " + "data that was present. "; errorMessage += "\r\n"; errorMessage += "\r\n"; errorMessage += "Client Endpoint: " + mxMessageEventArgs.Client.Endpoint + "\r\n"; errorMessage += "Message ID: " + messageID + "\r\n"; errorMessage += "Message Protocol: " + mxMessageEventArgs.ProtocolID + "\r\n"; errorMessage += "Length: " + length + "\r\n"; errorMessage += "Current Index: " + currentIndex + "\r\n"; errorMessage += "Total Packets: " + totalPackets + "\r\n"; errorMessage += "Payload Length: " + data.Length + "\r\n"; errorMessage += "Payload Length minus Offset: " + (data.Length - DataOffset) + "\r\n"; var exception = new InvalidDataException(errorMessage); exception.Data.Add("Payload", data); throw exception; } // Extract the fragment data. var fragmentData = new byte[length]; for (var i = 0; i < length; i++) { fragmentData[i] = data[i + DataOffset]; } // Set the fragment data into the received message. this.m_ActiveReceiveMessages[messageID].SetFragment(currentIndex, new Fragment(fragmentData, FragmentStatus.Received)); // Perform the receive update to fire events and finalize state if we have all the fragments. this.UpdateReceive(); }
/// <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(); }