예제 #1
0
        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();
            }
        }