コード例 #1
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);
                }
            }
        }
        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);
            }
        }