Пример #1
0
        public void InternalUpdate(out bool timeout)
        {
            lock (_sendLock)
            {
                for (ushort i = (ushort)(_outgoingLowestAckedSequence + 1); SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) < 0; i++)
                {
                    if (_sendSequencer.TryGet(i, out PendingOutgoingPacket value))
                    {
                        if ((NetTime.Now - value.LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier && (NetTime.Now - value.LastSent).TotalMilliseconds > config.ReliabilityMinPacketResendDelay)
                        {
                            if (value.Attempts >= config.ReliabilityMaxResendAttempts)
                            {
                                // If they don't ack the message, disconnect them
                                timeout = true;
                                return;
                            }

                            _sendSequencer.Update(i, new PendingOutgoingPacket()
                            {
                                Attempts        = (ushort)(value.Attempts + 1),
                                LastSent        = NetTime.Now,
                                FirstSent       = value.FirstSent,
                                Memory          = value.Memory,
                                NotificationKey = value.NotificationKey
                            });

                            connection.SendInternal(new ArraySegment <byte>(value.Memory.Buffer, (int)value.Memory.VirtualOffset, (int)value.Memory.VirtualCount), false);
                        }
                    }
                }
            }

            timeout = false;
        }
Пример #2
0
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            lock (_receiveLock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0)
                {
                    // Set the new sequence
                    _incomingLowestAckedSequence = sequence;

                    // Alloc pointers
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1);

                    // Alloc wrapper
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    return(pointers);
                }

                /* else
                 *      Logging.LogInfo("Dropped packet in UnreliableOrdered channel..."); */

                return(null);
            }
        }
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));
            // Read the raw fragment data
            ushort encodedFragment = (ushort)(payload.Array[payload.Offset + 2] | (ushort)(payload.Array[payload.Offset + 3] << 8));
            // The fragmentId is the last 15 least significant bits
            ushort fragment = (ushort)(encodedFragment & 32767);
            // IsFinal is the most significant bit
            bool isFinal = (ushort)((encodedFragment & 32768) >> 15) == 1;

            if (fragment >= config.MaxFragments)
            {
                if (Logging.CurrentLogLevel <= LogLevel.Error)
                {
                    Logging.LogError("FragmentId was too large. [FragmentId=" + fragment + "] [Config.MaxFragments=" + config.MaxFragments + "]. The fragment was silently dropped, expect a timeout.");
                }
                return(null);
            }

            lock (_receiveLock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 ||
                    ((_receiveSequencer.TryGet(sequence, out PendingIncomingPacketFragmented value) &&
                      (value.IsComplete || (value.Fragments != null && value.Fragments.VirtualCount > fragment && value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] != null)))))
                {
                    // We have already acked this message. Ack again

                    SendAckEncoded(sequence, encodedFragment);

                    return(null);
                }
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            lock (_receiveLock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0)
                {
                    // We have already acked this message. Ack again

                    SendAck(sequence);

                    return(null);
                }
                else
                {
                    // This is a future packet

                    // Add to sequencer
                    _incomingLowestAckedSequence = sequence;

                    // Send ack
                    SendAck(sequence);

                    // Alloc pointers
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1);

                    // Alloc a memory wrapper
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    return(pointers);
                }
            }
        }
Пример #5
0
        public void InternalUpdate()
        {
            long distance = SequencingUtils.Distance(_lastOutboundSequenceNumber, _incomingLowestAckedSequence, sizeof(ushort));

            for (ushort i = _incomingLowestAckedSequence; i < _incomingLowestAckedSequence + distance; i++)
            {
                if (_sendSequencer[i].Alive)
                {
                    if (_sendSequencer[i].Attempts > config.ReliabilityMaxResendAttempts)
                    {
                        // If they don't ack the message, disconnect them
                        connection.Disconnect(false);
                    }
                    else if ((DateTime.Now - _sendSequencer[i].LastSent).TotalMilliseconds > connection.Roundtrip * config.ReliabilityResendRoundtripMultiplier)
                    {
                        _sendSequencer[i] = new PendingOutgoingPacket()
                        {
                            Alive     = true,
                            Attempts  = (ushort)(_sendSequencer[i].Attempts + 1),
                            LastSent  = DateTime.Now,
                            FirstSent = _sendSequencer[i].FirstSent,
                            Memory    = _sendSequencer[i].Memory,
                            Sequence  = i
                        };

                        connection.SendRaw(new ArraySegment <byte>(_sendSequencer[i].Memory.Buffer, (int)_sendSequencer[i].Memory.VirtualOffset, (int)_sendSequencer[i].Memory.VirtualCount), false);
                    }
                }
            }
        }
Пример #6
0
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            lock (_receiveLock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _incomingAckedSequences.Contains(sequence))
                {
                    // We have already acked this message. Ack again
                    SendAck(sequence);

                    return(null);
                }
                else if (sequence == _incomingLowestAckedSequence + 1)
                {
                    // This is the "next" packet

                    do
                    {
                        // Remove previous
                        _incomingAckedSequences.Remove(_incomingLowestAckedSequence);

                        _incomingLowestAckedSequence++;
                    }while (_incomingAckedSequences.Contains((ushort)(_incomingLowestAckedSequence + 1)));

                    // Ack the new message
                    SendAck(sequence);

                    // Alloc pointers
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1);

                    // Alloc a memory wrapper
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    return(pointers);
                }
                else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_incomingAckedSequences.Contains(sequence))
                {
                    // This is a future packet

                    // Add to sequencer
                    _incomingAckedSequences.Add(sequence);

                    // Ack the new message
                    SendAck(sequence);

                    // Alloc pointers
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1);

                    // Alloc a memory wrapper
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    return(pointers);
                }

                return(null);
            }
        }
Пример #7
0
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore)
        {
            // Reliable has one message in equal no more than one out.
            hasMore = false;

            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            // Set the headerBytes
            headerBytes = 2;

            lock (_lock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _incomingAckedPackets.Contains(sequence))
                {
                    // We have already acked this message. Ack again

                    connection.IncomingDuplicatePackets++;
                    connection.IncomingDuplicateUserBytes  += (ulong)payload.Count - 2;
                    connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2;

                    SendAck(sequence);

                    return(null);
                }
                else if (sequence == _incomingLowestAckedSequence + 1)
                {
                    // This is the "next" packet

                    do
                    {
                        // Remove previous
                        _incomingAckedPackets.Remove(_incomingLowestAckedSequence);

                        _incomingLowestAckedSequence++;
                    }while (_incomingAckedPackets.Contains((ushort)(_incomingLowestAckedSequence + 1)));

                    // Ack the new message
                    SendAck(sequence);

                    return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
                }
                else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_incomingAckedPackets.Contains(sequence))
                {
                    // This is a future packet

                    // Add to sequencer
                    _incomingAckedPackets.Add(sequence);

                    SendAck(sequence);

                    return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
                }

                return(null);
            }
        }
Пример #8
0
        internal override void ResendPoll()
        {
            long distance = SequencingUtils.Distance(_lastOutboundSequenceNumber, _lowestAckedMessage, sizeof(ushort));

            for (ushort i = _lowestAckedMessage; i < _lowestAckedMessage + distance; i++)
            {
                if (_sendSequencer.HasMessage(i) && (DateTime.Now - _sendSequencer.Peek(i).LastSent).TotalMilliseconds > Constants.RESEND_DELAY)
                {
                    _sendSequencer.Peek(i).LastSentBy.SendPacket(_sendSequencer.Peek(i), _sendSequencer.Peek(i).LastSentTo);
                }
            }
        }
Пример #9
0
        public override ChanneledPacket HandleIncomingMessagePoll(byte[] buffer, int length, out bool hasMore)
        {
            hasMore = false;

            UnreliableSequencedPacket packet = new UnreliableSequencedPacket();

            packet.Read(buffer, length);

            long distance = SequencingUtils.Distance(packet.Sequence, _lastReceivedSequenceNumber, sizeof(ushort));

            if (distance > 0)
            {
                // This packet is a future packet
                _lastReceivedSequenceNumber = packet.Sequence;
                _receiveSequencer.Push(packet);
            }

            // Set the ack
            if (_sendSequencer.HasMessage(packet.AckSequence) && _sendSequencer.Peek(packet.AckSequence).ExplicitResponse != ExplicitResponseState.Ack)
            {
                packet.ExplicitResponse = ExplicitResponseState.Ack;
                OnMessageAck(packet.AckSequence);
            }

            // Resolve their acks & nacks from mask
            for (int i = 0; i < Constants.ACK_MASK_BITS; i++)
            {
                if (_sendSequencer.HasMessage(packet.AckSequence - i))
                {
                    ExplicitResponseState newState     = (packet.AckMask & (1UL << i)) != 0 ? ExplicitResponseState.Ack : ExplicitResponseState.Nack;
                    ExplicitResponseState currentState = _sendSequencer.Peek(packet.AckSequence - i).ExplicitResponse;

                    if (currentState != newState && currentState != ExplicitResponseState.Ack)
                    {
                        if (newState == ExplicitResponseState.Ack)
                        {
                            OnMessageAck(packet.AckSequence - i);
                        }
                        if (newState == ExplicitResponseState.Nack)
                        {
                            OnMessageNack(packet.AckSequence - i);
                        }
                    }

                    _sendSequencer.Peek(packet.AckSequence - i).ExplicitResponse = newState;
                }
            }


            return(distance > 0 ? packet : null);
        }
Пример #10
0
        private void SendAck(ushort sequence)
        {
            // Check the last ack time
            if ((DateTime.Now - _lastAckTimes[sequence]).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier)
            {
                // Set the last ack time
                _lastAckTimes[sequence] = DateTime.Now;

                // Alloc ack memory
                HeapMemory ackMemory = memoryManager.AllocHeapMemory(4 + (uint)(config.EnableMergedAcks ? config.MergedAckBytes : 0));

                // Write header
                ackMemory.Buffer[0] = HeaderPacker.Pack((byte)MessageType.Ack, false);
                ackMemory.Buffer[1] = (byte)channelId;

                // Write sequence
                ackMemory.Buffer[2] = (byte)sequence;
                ackMemory.Buffer[3] = (byte)(sequence >> 8);

                if (config.EnableMergedAcks)
                {
                    // Reset the memory
                    for (int i = 0; i < config.MergedAckBytes; i++)
                    {
                        ackMemory.Buffer[4 + i] = 0;
                    }

                    // Set the bit fields
                    for (int i = 0; i < config.MergedAckBytes * 8; i++)
                    {
                        ushort bitSequence = (ushort)(sequence - (i + 1));
                        bool   bitAcked    = SequencingUtils.Distance(bitSequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _receiveSequencer[bitSequence].Alive;

                        if (bitAcked)
                        {
                            // Set the ack time for this packet
                            _lastAckTimes[sequence] = DateTime.Now;
                        }

                        // Write single ack bit
                        ackMemory.Buffer[4 + (i / 8)] |= (byte)((bitAcked ? 1 : 0) << (7 - (i % 8)));
                    }
                }

                // Send ack
                connection.SendRaw(new ArraySegment <byte>(ackMemory.Buffer, 0, 4 + (config.EnableMergedAcks ? config.MergedAckBytes : 0)), false, (byte)(4 + (config.EnableMergedAcks ? config.MergedAckBytes : 0)));

                // Return memory
                memoryManager.DeAlloc(ackMemory);
            }
        }
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out bool hasMore)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _receiveSequencer[sequence].Alive)
            {
                // We have already acked this message. Ack again

                SendAck(sequence);

                hasMore = false;
                return(null);
            }
            else if (sequence == _incomingLowestAckedSequence + 1)
            {
                // This is the packet right after

                // If the one after is alive, we give set hasMore to true
                hasMore = _receiveSequencer[_incomingLowestAckedSequence + 2].Alive;

                _incomingLowestAckedSequence++;

                // Send ack
                SendAck(sequence);

                return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
            }
            else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_receiveSequencer[sequence].Alive)
            {
                // Alloc payload plus header memory
                HeapMemory memory = MemoryManager.Alloc((uint)payload.Count - 2);

                // Copy the payload
                Buffer.BlockCopy(payload.Array, payload.Offset + 2, memory.Buffer, 0, payload.Count - 2);

                // Add to sequencer
                _receiveSequencer[sequence] = new PendingIncomingPacket()
                {
                    Alive    = true,
                    Memory   = memory,
                    Sequence = sequence
                };

                // Send ack
                SendAck(sequence);
            }

            hasMore = false;
            return(null);
        }
Пример #12
0
        private void SendAck(ushort sequence)
        {
            // Check the last ack time
            if (!_lastAckTimes.TryGet(sequence, out NetTime value) || ((NetTime.Now - value).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier && (NetTime.Now - value).TotalMilliseconds > config.ReliabilityMinAckResendDelay))
            {
                // Set the last ack time
                _lastAckTimes.Set(sequence, NetTime.Now);

                // Alloc ack memory
                HeapMemory ackMemory = memoryManager.AllocHeapMemory(4 + (uint)(config.EnableMergedAcks ? config.MergedAckBytes : 0));

                // Write header
                ackMemory.Buffer[0] = HeaderPacker.Pack(MessageType.Ack);
                ackMemory.Buffer[1] = (byte)channelId;

                // Write sequence
                ackMemory.Buffer[2] = (byte)sequence;
                ackMemory.Buffer[3] = (byte)(sequence >> 8);

                if (config.EnableMergedAcks)
                {
                    // Reset the memory
                    for (int i = 0; i < config.MergedAckBytes; i++)
                    {
                        ackMemory.Buffer[4 + i] = 0;
                    }

                    // Set the bit fields
                    for (int i = 0; i < config.MergedAckBytes * 8; i++)
                    {
                        ushort bitSequence = (ushort)(sequence - (i + 1));
                        bool   bitAcked    = SequencingUtils.Distance(bitSequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _incomingAckedSequences.Contains(bitSequence);

                        if (bitAcked)
                        {
                            // Set the ack time for this packet
                            _lastAckTimes.Set(bitSequence, NetTime.Now);
                        }

                        // Write single ack bit
                        ackMemory.Buffer[4 + (i / 8)] |= (byte)((bitAcked ? 1 : 0) << (7 - (i % 8)));
                    }
                }

                // Send ack
                connection.SendInternal(new ArraySegment <byte>(ackMemory.Buffer, 0, 4 + (config.EnableMergedAcks ? config.MergedAckBytes : 0)), false);

                // Return memory
                memoryManager.DeAlloc(ackMemory);
            }
        }
Пример #13
0
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out bool hasMore)
        {
            // UnreliableSequenced has one message in equal no more than one out.
            hasMore = false;

            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0)
            {
                // Set the new sequence
                _incomingLowestAckedSequence = sequence;

                return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
            }

            return(null);
        }
Пример #14
0
        public override ChanneledPacket HandleIncomingMessagePoll(byte[] buffer, int size, out bool hasMore)
        {
            // Reliable has one message in equal no more than one out.
            hasMore = false;

            ReliablePacket packet = new ReliablePacket();

            packet.Read(buffer, size);

            if (packet.Sequence <= _incomingLowestAckedSequence || _incomingAckedPackets.ContainsKey(packet.Sequence))
            {
                // They didnt get our ack.

                // TODO: Send ack
                return(null);
            }
            else if (packet.Sequence == _incomingLowestAckedSequence + 1)
            {
                // This is the "next" packet

                do
                {
                    // Remove previous
                    _incomingAckedPackets.Remove(_incomingLowestAckedSequence);
                    _incomingLowestAckedSequence++;
                }while (packet.Sequence == _incomingLowestAckedSequence + 1);

                // TODO: Send ack

                return(packet);
            }
            else if (SequencingUtils.Distance(packet.Sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_incomingAckedPackets.ContainsKey(packet.Sequence))
            {
                // This is a future packet

                _incomingAckedPackets.Add(packet.Sequence, packet);

                // TODO: Send ack

                return(packet);
            }

            return(null);
        }
Пример #15
0
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // -> Sorting happens in the ConcurrentCircularQueue when messages are Enqueued

            //

            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            lock (_receiveLock)
            {
                if (_incomingAckedPackets.Contains(sequence))
                {
                    // We have already received this message. Ignore it.
                    return(null);
                }

                /* if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0)
                 * {
                 *      if (SequencingUtils.Distance(sequence, _lastPollSequence, sizeof(ushort)) > 0)
                 *      {
                 *              Logging.LogInfo("Skipping dropping packet since it's newer than _lastPollSequence (" + _lastPollSequence + ") | _incomingLowestAckedSequence: " + _incomingLowestAckedSequence + " | currentSequence: " + sequence);
                 *      }
                 * } */

                if (SequencingUtils.Distance(sequence, _lastPollSequence, sizeof(ushort)) > 0)
                // ! We're using _lastPollSequence instead of _incomingLowestAckedSequence to not drop old packets if we're still waiting for them to be polled by the game/MLAPI, which can still be sorted properly
                {
                    // Set the new sequence
                    _incomingLowestAckedSequence = sequence;
                    _incomingAckedPackets.Set(sequence, true);

                    // Alloc pointers
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1);

                    // Alloc wrapper
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    return(pointers);
                }

                return(null);
            }
        }
Пример #16
0
        public void InternalUpdate(out bool timeout)
        {
            lock (_sendLock)
            {
                for (ushort i = (ushort)(_outgoingLowestAckedSequence + 1); SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) <= 0; i++)
                {
                    if (_sendSequencer.TryGet(i, out PendingOutgoingPacketFragmented value))
                    {
                        for (int j = 0; j < value.Fragments.VirtualCount; j++)
                        {
                            if (value.Fragments.Pointers[j] != null)
                            {
                                PendingOutgoingFragment fragment = (PendingOutgoingFragment)value.Fragments.Pointers[j];

                                if ((NetTime.Now - fragment.LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier && (NetTime.Now - fragment.LastSent).TotalMilliseconds > config.ReliabilityMinPacketResendDelay)
                                {
                                    if (fragment.Attempts >= config.ReliabilityMaxResendAttempts)
                                    {
                                        // If they don't ack the message, disconnect them
                                        timeout = true;
                                        return;
                                    }

                                    fragment = new PendingOutgoingFragment()
                                    {
                                        Attempts  = (ushort)(fragment.Attempts + 1),
                                        LastSent  = NetTime.Now,
                                        FirstSent = fragment.FirstSent,
                                        Memory    = fragment.Memory
                                    };

                                    value.Fragments.Pointers[j] = fragment;

                                    connection.SendInternal(new ArraySegment <byte>(fragment.Memory.Buffer, (int)fragment.Memory.VirtualOffset, (int)fragment.Memory.VirtualCount), false);
                                }
                            }
                        }
                    }
                }
            }

            timeout = false;
        }
Пример #17
0
        public void InternalUpdate()
        {
            lock (_lock)
            {
                long distance = SequencingUtils.Distance(_lastOutboundSequenceNumber, _incomingLowestAckedSequence, sizeof(ushort));

                for (ushort i = _incomingLowestAckedSequence; i < _incomingLowestAckedSequence + distance; i++)
                {
                    if (_sendSequencer[i].Alive)
                    {
                        for (int j = 0; j < _sendSequencer[i].Fragments.VirtualCount; j++)
                        {
                            if (_sendSequencer[i].Fragments.Pointers[j] != null && ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Alive)
                            {
                                if (((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Attempts > config.ReliabilityMaxResendAttempts)
                                {
                                    // If they don't ack the message, disconnect them
                                    connection.Disconnect(false);
                                    return;
                                }
                                else if ((DateTime.Now - ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier)
                                {
                                    _sendSequencer[i].Fragments.Pointers[j] = new PendingOutgoingFragment()
                                    {
                                        Alive     = true,
                                        Attempts  = (ushort)(((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Attempts + 1),
                                        LastSent  = DateTime.Now,
                                        FirstSent = ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).FirstSent,
                                        Memory    = ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory,
                                        Sequence  = i
                                    };

                                    connection.SendRaw(new ArraySegment <byte>(((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory.Buffer, (int)((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory.VirtualOffset, (int)((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory.VirtualCount), false, 6);

                                    connection.OutgoingResentPackets++;
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #18
0
        public T this[int index]
        {
            get
            {
                int arrayIndex = NumberUtils.WrapMod(index, _array.Length);

                if (_indexes[arrayIndex] == index)
                {
                    return(_array[arrayIndex]);
                }
                else
                {
                    return(default(T));
                }
            }
            set
            {
                if (_resetOld)
                {
                    long distance = SequencingUtils.Distance((ulong)index, _lastHighestSequence, _wrapSize);

                    if (distance > 0)
                    {
                        for (int i = 1; i < distance; i++)
                        {
                            int resetArrayIndex = NumberUtils.WrapMod(((int)_lastHighestSequence + index + i), _array.Length);
                            _indexes[resetArrayIndex] = ((int)_lastHighestSequence + index + i);
                            _array[resetArrayIndex]   = default(T);
                        }

                        _lastHighestSequence = (ulong)index;
                    }
                }

                int arrayIndex = NumberUtils.WrapMod(index, _array.Length);
                _indexes[arrayIndex] = index;
                _array[arrayIndex]   = value;
            }
        }
Пример #19
0
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore)
        {
            // ReliableStateUpdate has one message in equal no more than one out.
            hasMore = false;

            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            // Set the headerBytes
            headerBytes = 2;

            lock (_lock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0)
                {
                    // We have already acked this message. Ack again

                    connection.IncomingDuplicatePackets++;
                    connection.IncomingDuplicateUserBytes  += (ulong)payload.Count - 2;
                    connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2;

                    SendAck(sequence);

                    return(null);
                }
                else
                {
                    // This is a future packet

                    // Add to sequencer
                    _incomingLowestAckedSequence = sequence;

                    SendAck(sequence);

                    return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
                }
            }
        }
Пример #20
0
        public bool TryEnqueue(T element, bool sortBySequence = false, int sequence = -1000)
        {
            // Cache writeHead and try to assign in a loop instead of pre incrementing writeHead in order to safe against buffer wraparounds

            while (true)
            {
                int positionWrite   = _writeHead;
                int arrayIndexWrite = NumberUtils.WrapMod(positionWrite, _array.Length);

                if (_indexes[arrayIndexWrite] == _writeHead && Interlocked.CompareExchange(ref _writeHead, positionWrite + 1, positionWrite) == positionWrite)
                {
                    if (sequence != -1000 && sortBySequence && Count > 0)
                    {
                        // Go from positionRead to positionWrite and if an element is bigger than sequence, that's where we will insert and update all the next ones to the right index
                        bool done = false;

                        /* string s1 = "";
                        *  string s2 = ""; */
                        lock ("sortLock")
                        {
                            for (int k = _readHead; k <= _writeHead; k++)
                            {
                                int arrayIndex = NumberUtils.WrapMod(k, _array.Length);

                                //string s0 = _sequences[arrayIndex] + " ";

                                if (_sequences[arrayIndex] != -1000 && SequencingUtils.Distance((ulong)_sequences[arrayIndex], (ulong)sequence, sizeof(ushort)) > 0)
                                {
                                    if (k != _writeHead)
                                    {
                                        for (int i = _writeHead + 1; i > k; i--)
                                        {
                                            int previousAI = NumberUtils.WrapMod(i - 1, _array.Length);
                                            int aI         = NumberUtils.WrapMod(i, _array.Length);

                                            /* if (i != _writeHead + 1)
                                             *      s1 = _sequences[aI] + " " + s1;
                                             * s2 = _sequences[previousAI] + " " + s2; */

                                            _array[aI] = _array[previousAI];
                                            Thread.MemoryBarrier();
                                            _indexes[aI]   = _indexes[previousAI] + 1;
                                            _sequences[aI] = _sequences[previousAI];
                                        }

                                        _array[arrayIndex] = element;
                                        Thread.MemoryBarrier();
                                        _sequences[arrayIndex] = sequence;

                                        /* Logging.LogInfo("Needs sorting: ... " + s0 + "| " + s1 + "*" + sequence + " (" + _readHead + " - " + _writeHead + ")");
                                         * Logging.LogInfo("-----  Sorted: ... *" + sequence + " | " + s2 + " (" + _readHead + " - " + _writeHead + ")"); */

                                        done = true;
                                        break;
                                    }
                                }
                            }

                            if (!done)
                            {
                                //Logging.LogInfo("- No sorting: " + s0 + s + sequence);

                                _array[arrayIndexWrite] = element;
                                Thread.MemoryBarrier();
                                _indexes[arrayIndexWrite]   = positionWrite + 1;
                                _sequences[arrayIndexWrite] = sequence;
                            }
                        }
                    }
                    else
                    {
                        _array[arrayIndexWrite] = element;
                        Thread.MemoryBarrier();
                        _indexes[arrayIndexWrite] = positionWrite + 1;
                        if (sortBySequence)
                        {
                            _sequences[arrayIndexWrite] = sequence;
                        }
                    }

                    return(true);
                }
                else if (_indexes[arrayIndexWrite] < positionWrite)
                {
                    // Overflow, it cannot be assigned as a forward enqueue did not occur
                    return(false);
                }
            }
        }
Пример #21
0
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            // Set the headerBytes
            headerBytes = 2;

            lock (_lock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _receiveSequencer[sequence].Alive)
                {
                    // We have already acked this message. Ack again

                    connection.IncomingDuplicatePackets++;
                    connection.IncomingDuplicateUserBytes  += (ulong)payload.Count - 2;
                    connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2;

                    SendAck(sequence);

                    hasMore = false;
                    return(null);
                }
                else if (sequence == _incomingLowestAckedSequence + 1)
                {
                    // This is the packet right after

                    // If the one after is alive, we give set hasMore to true
                    hasMore = _receiveSequencer[_incomingLowestAckedSequence + 2].Alive;

                    _incomingLowestAckedSequence++;

                    // Send ack
                    SendAck(sequence);

                    return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
                }
                else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0)
                {
                    // Future packet

                    PendingIncomingPacket unsafeIncoming = _receiveSequencer.GetUnsafe(sequence, out bool isSafe);

                    if (unsafeIncoming.Alive && !isSafe)
                    {
                        if (Logging.CurrentLogLevel <= LogLevel.Error)
                        {
                            Logging.LogError("Incoming packet window is exhausted. Disconnecting");
                        }

                        connection.Disconnect(false);

                        hasMore = false;
                        return(null);
                    }
                    else if (!_receiveSequencer[sequence].Alive)
                    {
                        // Alloc payload plus header memory
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 2);

                        // Copy the payload
                        Buffer.BlockCopy(payload.Array, payload.Offset + 2, memory.Buffer, 0, payload.Count - 2);

                        // Add to sequencer
                        _receiveSequencer[sequence] = new PendingIncomingPacket()
                        {
                            Alive    = true,
                            Memory   = memory,
                            Sequence = sequence
                        };

                        // Send ack
                        SendAck(sequence);
                    }
                }

                hasMore = false;
                return(null);
            }
        }
Пример #22
0
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));
            // Read the raw fragment data
            ushort encodedFragment = (ushort)(payload.Array[payload.Offset + 2] | (ushort)(payload.Array[payload.Offset + 3] << 8));
            // The fragmentId is the last 15 least significant bits
            ushort fragment = (ushort)(encodedFragment & 32767);
            // IsFinal is the most significant bit
            bool isFinal = (ushort)((encodedFragment & 32768) >> 15) == 1;

            if (fragment >= config.MaxFragments)
            {
                if (Logging.CurrentLogLevel <= LogLevel.Error)
                {
                    Logging.LogError("FragmentId was too large. [FragmentId=" + fragment + "] [Config.MaxFragments=" + config.MaxFragments + "]. The fragment was silently dropped, expect a timeout.");
                }
                return(null);
            }

            lock (_receiveLock)
            {
                // If the sequence is older than the last one we sent to user OR the packet is already acked OR the sequence is alive and its complete OR (the sequence is alive AND the fragments is alloced AND the alloced fragment count is larger than the fragment (I.E, the fragment is actually alloced) AND the fragment is not null AND the fragment is not dead))
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 ||
                    (_incomingAckedSequences.Contains(sequence)) ||
                    (_receiveSequencer.TryGet(sequence, out PendingIncomingPacketFragmented value) && (value.IsComplete || (value.Fragments.VirtualCount > fragment && value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] != null))))
                {
                    // We have already acked this message. Ack again

                    SendAckEncoded(sequence, encodedFragment);

                    return(null);
                }
                else
                {
                    // This is a packet after the last. One that is not yet completed

                    if (!_receiveSequencer.CanUpdateOrSet(sequence))
                    {
                        // If we cant update or set, that means the window is full and we are not in the window.

                        if (Logging.CurrentLogLevel <= LogLevel.Warning)
                        {
                            Logging.LogWarning("Incoming packet window is exhausted. Expect delays");
                        }
                        return(null);
                    }

                    if (!_receiveSequencer.TryGet(sequence, out value))
                    {
                        // If this is the first fragment we ever get, index the data.

                        HeapPointers fragmentPointers = memoryManager.AllocHeapPointers((uint)fragment + 1);

                        value = new PendingIncomingPacketFragmented()
                        {
                            Fragments = fragmentPointers,
                            Size      = isFinal ? (ushort?)(fragment + 1) : null
                        };

                        _receiveSequencer.Set(sequence, value);
                    }
                    else
                    {
                        // If the first fragment we got was fragment 1 / 500. The fragments array will only be of size 128. We need to potentially resize it
                        if (value.Fragments.Pointers.Length - value.Fragments.VirtualOffset <= fragment)
                        {
                            // We need to expand the fragments array.

                            // Alloc new array
                            HeapPointers newPointers = memoryManager.AllocHeapPointers((uint)fragment + 1);

                            // Copy old values
                            Array.Copy(value.Fragments.Pointers, newPointers.Pointers, value.Fragments.Pointers.Length);

                            // Return the memory for the old
                            memoryManager.DeAlloc(value.Fragments);

                            // Update the index
                            value = new PendingIncomingPacketFragmented()
                            {
                                Fragments = newPointers,
                                Size      = isFinal ? (ushort?)(fragment + 1) : value.Size
                            };

                            _receiveSequencer.Update(sequence, value);
                        }

                        // We might also have to expand the virtual count
                        if (value.Fragments.VirtualCount <= fragment)
                        {
                            // Update the new virtual count
                            value.Fragments.VirtualCount = (uint)fragment + 1;

                            // Update the struct to set the size if it has changed (TODO: Check if needed)
                            value = new PendingIncomingPacketFragmented()
                            {
                                Fragments = value.Fragments,
                                Size      = isFinal ? (ushort?)(fragment + 1) : value.Size
                            };

                            _receiveSequencer.Update(sequence, value);
                        }
                    }

                    // If the fragment is null OR the fragment is DEAD
                    if (value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] == null)
                    {
                        // Alloc some memory for the fragment
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 4);

                        // Copy the payload
                        Buffer.BlockCopy(payload.Array, payload.Offset + 4, memory.Buffer, 0, payload.Count - 4);

                        // Add fragment to index
                        value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] = memory;
                    }

                    // Send ack
                    SendAckEncoded(sequence, encodedFragment);

                    // If this sequence just completed. Return the memory
                    if (value.IsComplete)
                    {
                        if (sequence == (ushort)(_incomingLowestAckedSequence + 1))
                        {
                            // This is the next packet.

                            do
                            {
                                // Remove previous
                                _incomingAckedSequences.Remove(_incomingLowestAckedSequence);

                                _incomingLowestAckedSequence++;
                            }while (_incomingAckedSequences.Contains((ushort)(_incomingLowestAckedSequence + 1)));
                        }
                        else
                        {
                            // This is a future one
                            _incomingAckedSequences.Add(sequence);
                        }

                        // Get the total size of all fragments
                        uint totalSize = value.TotalByteSize;

                        // Alloc memory for that large segment
                        HeapMemory memory = memoryManager.AllocHeapMemory(totalSize);

                        // Keep track of where we are, fragments COULD have different sizes.
                        int bufferPosition = 0;

                        if (value.Fragments != null)
                        {
                            // Copy all the parts
                            for (int i = 0; i < value.Fragments.VirtualCount; i++)
                            {
                                // Copy fragment to final buffer
                                Buffer.BlockCopy(((HeapMemory)value.Fragments.Pointers[value.Fragments.VirtualOffset + i]).Buffer, (int)((HeapMemory)value.Fragments.Pointers[value.Fragments.VirtualOffset + i]).VirtualOffset, memory.Buffer, bufferPosition, (int)((HeapMemory)value.Fragments.Pointers[value.Fragments.VirtualOffset + i]).VirtualCount);

                                bufferPosition += (int)((HeapMemory)value.Fragments.Pointers[value.Fragments.VirtualOffset + i]).VirtualCount;
                            }
                        }

                        // Free the memory of all the individual fragments
                        value.DeAlloc(memoryManager);

                        // Kill
                        _receiveSequencer.Remove(sequence);

                        // Alloc pointers
                        HeapPointers pointers = memoryManager.AllocHeapPointers(1);

                        // Alloc a memory wrapper
                        pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(memory);

                        return(pointers);
                    }

                    return(null);
                }
            }
        }
Пример #23
0
        public void HandleAck(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));
            // Read the raw fragment data
            ushort encodedFragment = (ushort)(payload.Array[payload.Offset + 2] | (ushort)(payload.Array[payload.Offset + 3] << 8));
            // The fragmentId is the last 15 least significant bits
            ushort fragment = (ushort)(encodedFragment & 32767);
            // IsFinal is the most significant bit
            bool isFinal = (ushort)((encodedFragment & 32768) >> 15) == 1;

            lock (_sendLock)
            {
                if (_sendSequencer.TryGet(sequence, out PendingOutgoingPacketFragmented value) && value.Fragments.VirtualCount > fragment && value.Fragments.Pointers[fragment] != null)
                {
                    // Dealloc the memory held by the sequencer for the packet
                    ((PendingOutgoingFragment)value.Fragments.Pointers[fragment]).DeAlloc(memoryManager);

                    // TODO: Remove roundtripping from channeled packets and make specific ping-pong packets

                    // Get the roundtrp
                    ulong roundtrip = (ulong)Math.Round((NetTime.Now - ((PendingOutgoingFragment)value.Fragments.Pointers[fragment]).FirstSent).TotalMilliseconds);

                    // Report to the connection
                    connection.AddRoundtripSample(roundtrip);

                    // Kill the fragment packet
                    value.Fragments.Pointers[fragment] = null;

                    bool hasAllocatedAndAliveFragments = false;
                    for (int i = 0; i < value.Fragments.VirtualCount; i++)
                    {
                        if (value.Fragments.Pointers[i] != null)
                        {
                            hasAllocatedAndAliveFragments = true;
                            break;
                        }
                    }

                    if (!hasAllocatedAndAliveFragments)
                    {
                        // Notify user that the packet was acked
                        ChannelRouter.HandlePacketAckedByRemote(connection, channelId, value.NotificationKey);

                        // Dealloc the wrapper packet
                        value.DeAlloc(memoryManager);

                        // Kill the wrapper packet
                        _sendSequencer.Remove(sequence);

                        if (sequence == (ushort)(_outgoingLowestAckedSequence + 1))
                        {
                            // This was the next one.
                            _outgoingLowestAckedSequence++;
                        }
                    }
                }

                // Loop from the lowest ack we got
                for (ushort i = _outgoingLowestAckedSequence; !_sendSequencer.TryGet(i, out value) && SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) <= 0; i++)
                {
                    _outgoingLowestAckedSequence = i;
                }

                // Check if we can start draining pending pool
                while (_pendingSends.Count > 0 && _sendSequencer.CanSet((ushort)(_lastOutgoingSequence + 1)))
                {
                    // Dequeue the pending
                    PendingSend pending = _pendingSends.Dequeue();

                    // Sequence it
                    CreateOutgoingMessageInternal(new ArraySegment <byte>(pending.Memory.Buffer, (int)pending.Memory.VirtualOffset, (int)pending.Memory.VirtualCount), pending.NoMerge, pending.NotificationKey);

                    // Dealloc
                    memoryManager.DeAlloc(pending.Memory);
                }
            }
        }
Пример #24
0
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));
            // Read the raw fragment data
            ushort encodedFragment = (ushort)(payload.Array[payload.Offset + 2] | (ushort)(payload.Array[payload.Offset + 3] << 8));
            // The fragmentId is the last 15 least significant bits
            ushort fragment = (ushort)(encodedFragment & 32767);
            // IsFinal is the most significant bit
            bool isFinal = (ushort)((encodedFragment & 32768) >> 15) == 1;

            // Set the headerBytes
            headerBytes = 4;

            if (fragment > config.MaxFragments)
            {
                if (Logging.CurrentLogLevel <= LogLevel.Error)
                {
                    Logging.LogError("FragmentId was too large. [FragmentId=" + fragment + "] [Config.MaxFragments=" + config.MaxFragments + "]. The fragment was silently dropped, expect a timeout.");
                }
                hasMore = false;
                return(null);
            }

            lock (_lock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 ||
                    (_receiveSequencer[sequence].Alive && _receiveSequencer[sequence].IsComplete) ||
                    (_receiveSequencer[sequence].Alive && _receiveSequencer[sequence].Fragments != null && _receiveSequencer[sequence].Fragments.VirtualCount > fragment && _receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment] != null && !((HeapMemory)_receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment]).isDead))
                {
                    // We have already acked this message. Ack again

                    connection.IncomingDuplicatePackets++;
                    connection.IncomingDuplicateUserBytes  += (ulong)payload.Count - 2;
                    connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2;

                    SendAckEncoded(sequence, encodedFragment);

                    hasMore = false;

                    return(null);
                }
                else
                {
                    // This is a packet after the last. One that is not yet completed

                    PendingIncomingPacket unsafeIncoming = _receiveSequencer.GetUnsafe(sequence, out bool isSafe);

                    if (unsafeIncoming.Alive && !isSafe)
                    {
                        if (Logging.CurrentLogLevel <= LogLevel.Error)
                        {
                            Logging.LogError("Incoming packet window is exhausted. Disconnecting");
                        }

                        connection.Disconnect(false);

                        hasMore = false;
                        return(null);
                    }
                    else if (!_receiveSequencer[sequence].Alive)
                    {
                        // If this is the first fragment we ever get, index the data.

                        // TODO: Alloc more size and just expand later in the pointer array

                        HeapPointers fragmentPointers = memoryManager.AllocHeapPointers((uint)fragment + 1);

                        _receiveSequencer[sequence] = new PendingIncomingPacket()
                        {
                            Alive     = true,
                            Fragments = fragmentPointers,
                            Sequence  = sequence,
                            Size      = isFinal ? (ushort?)(fragment + 1) : null
                        };
                    }
                    else
                    {
                        // If the first fragment we got was fragment 1 / 500. The fragments array will only be of size 128. We need to potentially resize it
                        if (_receiveSequencer[sequence].Fragments.Pointers.Length - _receiveSequencer[sequence].Fragments.VirtualOffset <= fragment)
                        {
                            // We need to expand the fragments array.

                            // Alloc new array
                            HeapPointers newPointers = memoryManager.AllocHeapPointers((uint)fragment + 1);

                            // Copy old values
                            Array.Copy(_receiveSequencer[sequence].Fragments.Pointers, newPointers.Pointers, _receiveSequencer[sequence].Fragments.Pointers.Length);

                            // Return the memory for the old
                            memoryManager.DeAlloc(_receiveSequencer[sequence].Fragments);

                            // Update the index
                            _receiveSequencer[sequence] = new PendingIncomingPacket()
                            {
                                Fragments = newPointers,
                                Alive     = _receiveSequencer[sequence].Alive,
                                Sequence  = _receiveSequencer[sequence].Sequence,
                                Size      = isFinal ? (ushort?)(fragment + 1) : _receiveSequencer[sequence].Size
                            };
                        }

                        // We might also have to expand the virtual count
                        if (_receiveSequencer[sequence].Fragments.VirtualCount <= fragment)
                        {
                            // Update the new virtual count
                            _receiveSequencer[sequence].Fragments.VirtualCount = (uint)fragment + 1;

                            // Update the struct to set the size if it has changed (TODO: Check if needed)
                            _receiveSequencer[sequence] = new PendingIncomingPacket()
                            {
                                Fragments = _receiveSequencer[sequence].Fragments,
                                Alive     = _receiveSequencer[sequence].Alive,
                                Sequence  = _receiveSequencer[sequence].Sequence,
                                Size      = isFinal ? (ushort?)(fragment + 1) : _receiveSequencer[sequence].Size
                            };
                        }
                    }

                    if (_receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment] == null || ((HeapMemory)_receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment]).isDead)
                    {
                        // Alloc some memory for the fragment
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 4);

                        // Copy the payload
                        Buffer.BlockCopy(payload.Array, payload.Offset + 4, memory.Buffer, 0, payload.Count - 4);

                        // Add fragment to index
                        _receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment] = memory;
                    }

                    // Send ack
                    SendAckEncoded(sequence, encodedFragment);

                    // Sequenced never returns the original memory. Thus we need to return null and tell the caller to Poll instead.
                    hasMore = _receiveSequencer[_incomingLowestAckedSequence + 1].Alive && _receiveSequencer[_incomingLowestAckedSequence + 1].IsComplete;

                    return(null);
                }
            }
        }
Пример #25
0
        private void HandleAck(ushort sequence)
        {
            lock (_sendLock)
            {
                if (_sendSequencer.TryGet(sequence, out PendingOutgoingPacket value))
                {
                    // Notify the user about the ack
                    ChannelRouter.HandlePacketAckedByRemote(connection, channelId, value.NotificationKey);

                    // Dealloc the memory held by the sequencer
                    memoryManager.DeAlloc(value.Memory);

                    // TODO: Remove roundtripping from channeled packets and make specific ping-pong packets

                    // Get the roundtrp
                    ulong roundtrip = (ulong)Math.Round((NetTime.Now - value.FirstSent).TotalMilliseconds);

                    // Report to the connection
                    connection.AddRoundtripSample(roundtrip);

                    // Kill the packet
                    _sendSequencer.Remove(sequence);

                    if (sequence == (ushort)(_outgoingLowestAckedSequence + 1))
                    {
                        // This was the next one.
                        _outgoingLowestAckedSequence++;
                    }
                }

                // Loop from the lowest ack we got
                for (ushort i = _outgoingLowestAckedSequence; !_sendSequencer.Contains(i) && SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) <= 0; i++)
                {
                    _outgoingLowestAckedSequence = i;
                }

                // Check if we can start draining pending pool
                while (_pendingSends.Count > 0 && _sendSequencer.CanSet((ushort)(_lastOutgoingSequence + 1)))
                {
                    // Dequeue the pending
                    PendingSend pending = _pendingSends.Dequeue();

                    // Sequence it
                    CreateOutgoingMessageInternal(new ArraySegment <byte>(pending.Memory.Buffer, (int)pending.Memory.VirtualOffset, (int)pending.Memory.VirtualCount), pending.NoMerge, pending.NotificationKey);

                    // Dealloc
                    memoryManager.DeAlloc(pending.Memory);
                }
            }
        }
Пример #26
0
        public bool this[T key]
        {
            get
            {
                if (_indexLookup.ContainsKey(key))
                {
                    int index = _indexLookup[key];

                    int arrayIndex = NumberUtils.WrapMod(index, _indexes.Length);

                    if (_indexes[arrayIndex] == index)
                    {
                        return(true);
                    }
                }

                return(false);
            }
            set
            {
                ushort index;

                if (_indexLookup.ContainsKey(key))
                {
                    index = _indexLookup[key];
                }
                else
                {
                    index = _indexCounter;
                    _indexCounter++;
                }

                if (_resetOld)
                {
                    long distance = SequencingUtils.Distance(index, _lastHighestSequence, _wrapSize);

                    if (distance > 0)
                    {
                        for (ushort i = 1; i < distance; i++)
                        {
                            int resetArrayIndex = NumberUtils.WrapMod((_lastHighestSequence + index + i), _indexes.Length);
                            _indexes[resetArrayIndex] = (ushort)(_lastHighestSequence + index + i);

                            if (_indexLookup.ContainsKey(_array[resetArrayIndex]))
                            {
                                _indexLookup.Remove(_array[resetArrayIndex]);
                            }

                            _array[resetArrayIndex] = default(T);
                        }

                        _lastHighestSequence = index;
                    }
                }

                int arrayIndex = NumberUtils.WrapMod(index, _indexes.Length);

                if (_indexLookup.ContainsKey(_array[arrayIndex]))
                {
                    _indexLookup.Remove(_array[arrayIndex]);
                }

                if (value)
                {
                    _indexLookup.Add(key, index);
                }

                _indexes[arrayIndex] = index;
                _array[arrayIndex]   = key;
            }
        }
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            lock (_receiveLock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _receiveSequencer.Contains(sequence))
                {
                    // We have already acked this message. Ack again

                    SendAck(sequence);

                    return(null);
                }
                else if (sequence == (ushort)(_incomingLowestAckedSequence + 1))
                {
                    // This is the packet right after

                    _incomingLowestAckedSequence++;

                    // Send ack
                    SendAck(sequence);

                    uint additionalPackets = 0;

                    // Count all the additional sequential packets that are ready
                    for (int i = 1; (_receiveSequencer.TryGet((ushort)(_incomingLowestAckedSequence + i), out PendingIncomingPacket value)); i++)
                    {
                        additionalPackets++;
                    }

                    // Allocate pointers (alloc size 1, we might need more)
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1 + additionalPackets);

                    // Point the first pointer to the memory that is known.
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    for (int i = 0; _receiveSequencer.TryGet((ushort)(_incomingLowestAckedSequence + 1), out PendingIncomingPacket value); i++)
                    {
                        // Update lowest incoming
                        ++_incomingLowestAckedSequence;

                        // Set the memory
                        pointers.Pointers[1 + i] = memoryManager.AllocMemoryWrapper(value.Memory);

                        // Kill
                        _receiveSequencer.Remove(_incomingLowestAckedSequence);
                    }

                    return(pointers);
                }
                else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0)
                {
                    // Future packet

                    if (!_receiveSequencer.CanUpdateOrSet(sequence))
                    {
                        // If we cant update or set, that means the window is full and we are not in the window.

                        if (Logging.CurrentLogLevel <= LogLevel.Warning)
                        {
                            Logging.LogWarning("Incoming packet window is exhausted. Expect delays");
                        }
                        return(null);
                    }

                    if (!_receiveSequencer.Contains(sequence))
                    {
                        // Alloc payload plus header memory
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 2);

                        // Copy the payload
                        Buffer.BlockCopy(payload.Array, payload.Offset + 2, memory.Buffer, 0, payload.Count - 2);

                        // Add to sequencer
                        _receiveSequencer.Set(sequence, new PendingIncomingPacket()
                        {
                            Memory = memory
                        });

                        // Send ack
                        SendAck(sequence);
                    }
                }

                return(null);
            }
        }