public HeapMemory HandlePoll()
        {
            lock (_lock)
            {
                if (_receiveSequencer[_incomingLowestAckedSequence + 1].Alive)
                {
                    ++_incomingLowestAckedSequence;

                    // HandlePoll gives the memory straight to the user, they are responsible for deallocing to prevent leaks
                    HeapMemory memory = _receiveSequencer[_incomingLowestAckedSequence].Memory;

                    // Kill
                    _receiveSequencer[_incomingLowestAckedSequence] = new PendingIncomingPacket()
                    {
                        Alive    = false,
                        Sequence = 0
                    };


                    return(memory);
                }

                return(null);
            }
        }
Esempio n. 2
0
        public HeapMemory HandlePoll()
        {
            lock (_lock)
            {
                // Get the next packet that is not yet given to the user.
                PendingIncomingPacket nextPacket = _receiveSequencer[_incomingLowestAckedSequence + 1];

                if (nextPacket.Alive && nextPacket.IsComplete)
                {
                    ++_incomingLowestAckedSequence;

                    // Get the total size of all fragments
                    uint totalSize = nextPacket.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 (nextPacket.Fragments != null)
                    {
                        // Copy all the parts
                        for (int i = 0; i < nextPacket.Fragments.VirtualCount; i++)
                        {
                            // Copy fragment to final buffer
                            Buffer.BlockCopy(((HeapMemory)nextPacket.Fragments.Pointers[nextPacket.Fragments.VirtualOffset + i]).Buffer, (int)((HeapMemory)nextPacket.Fragments.Pointers[nextPacket.Fragments.VirtualOffset + i]).VirtualOffset, memory.Buffer, bufferPosition, (int)((HeapMemory)nextPacket.Fragments.Pointers[nextPacket.Fragments.VirtualOffset + i]).VirtualCount);

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

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

                    // Kill
                    _receiveSequencer[_incomingLowestAckedSequence] = new PendingIncomingPacket()
                    {
                        Alive     = false,
                        Sequence  = 0,
                        Size      = null,
                        Fragments = null
                    };


                    // HandlePoll gives the memory straight to the user, they are responsible for deallocing to prevent leaks
                    return(memory);
                }

                return(null);
            }
        }
        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);
        }
Esempio n. 4
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);
                }
            }
        }
        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);
            }
        }