public void AckSeq(ushort seq) { if (Count == 0) { return; } int lastInd = Last - 1 >= 0 ? Last - 1 : Max - 1; ushort firstSeq = Items[First].Seq; ushort lastSeq = Items[lastInd].Seq; // If the seq isn't inside the range of our window then we don't care about it if (!SequenceHelper.SeqIsInsideRangeInclusive(firstSeq, lastSeq, seq, Max)) { return; } // drop moves off the front of the window until the window starts at seq + 1 or count = 0 int targetSeq = seq + 1; while (Count > 0 && Items[First].Seq != targetSeq) { First = ++First < Max ? First : 0; Count--; } }
private void OnAckedTransmission(PacketTransmissionRecord record) { // Drop the start of our current ack flag since we know that the remote stream // knows about the sequence that it represents // I think this covers all edge cases? if (record.AckFlag.SeqCount <= 0) { return; } if (_remoteSeqAckFlag.StartSeq == record.AckFlag.EndSeq) { _remoteSeqAckFlag.DropStartSequence(); } else if (SequenceHelper.SeqIsAheadButInsideWindow32(_remoteSeqAckFlag.StartSeq, record.AckFlag.EndSeq)) { _remoteSeqAckFlag.DropStartSequenceUntilItEquals((byte)(record.AckFlag.EndSeq + 1)); } }
public void UpdateIncoming(bool host = false) { if (_dataReceivedEvents.Count == 0) { return; } _log.Debug($"UPDATE INCOMING - Frame: {Time.frameCount} Seq: {_seq}\n"); DebugGraph.Log("Packets Received", _dataReceivedEvents.Count); try { // Process data received events _log.Debug($"Received {_dataReceivedEvents.Count} packets"); for (int i = 0; i < _dataReceivedEvents.Count; i++) { // Get data reader from evt which contains the binary data for the packet NetPacketReader reader = _dataReceivedEvents[i].DataReader; // Deserialize packet (including header) _header.Deserialize(reader); _log.Debug($"Received Packet Sequence: {_header.Seq}"); _log.Debug($"Packet AckFlag: {_header.AckFlag}"); _log.Debug($"Local AckedFlag- before: {_remoteSeqAckFlag}"); if (_remoteSeqAckFlag.SeqCount == 0) { // No sequences in the flag so just initialize it with this sequence being ACKed _remoteSeqAckFlag.InitWithAckedSequence(_header.Seq); } else if (SequenceHelper.SeqIsAheadButInsideWindow32(_remoteSeqAckFlag.EndSeq, _header.Seq)) { _log.Debug($"Received sequence {_header.Seq} is ahead of the last sequence in our ack flag: {_remoteSeqAckFlag.EndSeq}"); // The seq is ahead of the range of our flag (ie a new seq) but we want to NACK any that // sequences that are in between the last sequence we ACKed, and this sequence we are now receiving // since they must have been dropped (or delivered out of order) while (_remoteSeqAckFlag.EndSeq != (byte)(_header.Seq - 1)) { _remoteSeqAckFlag.NackNextSequence(); _log.Debug($"NACKed sequence {_remoteSeqAckFlag.EndSeq}"); } // Ack this sequence in our flag _remoteSeqAckFlag.AckNextSequence(); } else { // This packet was delivered out of order // or is outside the expected window so don't process it further _log.Debug($"{_header.Seq} - SKIPPED UNEXPECTED"); continue; } // Generate notifications based on ACKs received from the remote stream if (_header.AckFlag.SeqCount > 0) { if (_seqLastNotified == -1) { _log.Debug("Initializing SeqLastNotified"); // This is the start of us notifying packets.. if any packets were sent but aren't // included in this ack flag then they must have been dropped while (_transmissionRecords.Peek().Seq != _header.AckFlag.StartSeq) { PacketTransmissionRecord record = _transmissionRecords.Dequeue(); _seqLastNotified = record.Seq; _transmissionNotifications.Add(false); _log.Debug($"Seq {record.Seq} was dropped"); } // Notify based on sequences in flag GenerateNotificationsFromAckFlagAndUpdateSeqLastNotified(_header.AckFlag); } else if (SequenceHelper.SeqIsAheadButInsideWindow32((byte)_seqLastNotified, _header.AckFlag.StartSeq)) { // NACK all packets up until the start of this ACK flag because they must have been lost or delivered out of order while (_seqLastNotified != (byte)(_header.AckFlag.StartSeq - 1)) { _transmissionRecords.Dequeue(); _transmissionNotifications.Add(false); _seqLastNotified = ++_seqLastNotified <= byte.MaxValue ? _seqLastNotified : 0; _log.Debug($"Sequence: {_seqLastNotified} was dropped"); } // Notify based on sequences in flag GenerateNotificationsFromAckFlagAndUpdateSeqLastNotified(_header.AckFlag); } else if (SequenceHelper.SeqIsInsideRangeInclusive(_header.AckFlag.StartSeq, _header.AckFlag.EndSeq, (byte)_seqLastNotified)) { _log.Debug($"{_seqLastNotified} is inside ack flag range"); // Drop sequences we have already notified _header.AckFlag.DropStartSequenceUntilItEquals((byte)(_seqLastNotified + 1)); // Notify based on sequences remaining in flag GenerateNotificationsFromAckFlagAndUpdateSeqLastNotified(_header.AckFlag); } } _log.Debug("Finished generating notifications"); // Give stream to each system to processors in the order they were added foreach (IPacketStreamReader streamProcessor in _streamProcessors) { streamProcessor.ReadPacketStream(reader); } } _log.Debug($"SeqLastNotified - After: {_seqLastNotified}"); _log.Debug($"Generated {_transmissionNotifications.Count} transmission notifications"); _log.Debug($"There are now { _transmissionRecords.Count} remaining transmission records in the queue"); // Give notifications to any stream writers that are interested in whether or not their transmissions made it foreach (IPacketTransmissionNotificationReceiver notificationReceiver in _notificationReceivers) { notificationReceiver.ReceiveNotifications(_transmissionNotifications); } } catch (Exception e) { _log.Debug(e.Message); throw; } finally { _dataReceivedEvents.Clear(); _transmissionNotifications.Clear(); } }