Exemplo n.º 1
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));

            if (_sendSequencer[sequence].Alive)
            {
                // Dealloc the memory held by the sequencer
                MemoryManager.DeAlloc(_sendSequencer[sequence].Memory);

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

                // Get the roundtrp
                ulong roundtrip = (ulong)Math.Round((DateTime.Now - _sendSequencer[sequence].FirstSent).TotalMilliseconds);

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

                // Kill the packet
                _sendSequencer[sequence] = new PendingOutgoingPacket()
                {
                    Alive    = false,
                    Sequence = sequence
                };
            }

            for (ushort i = sequence; _sendSequencer[i].Alive; i++)
            {
                _incomingLowestAckedSequence = i;
            }
        }
Exemplo n.º 2
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);
                    }
                }
            }
        }
Exemplo n.º 3
0
        private void HandleAck(ushort sequence)
        {
            lock (_lock)
            {
                if (_sendSequencer[sequence].Alive)
                {
                    // Add statistics
                    connection.OutgoingConfirmedPackets++;

                    // Dealloc the memory held by the sequencer
                    memoryManager.DeAlloc(_sendSequencer[sequence].Memory);

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

                    // Get the roundtrp
                    ulong roundtrip = (ulong)Math.Round((DateTime.Now - _sendSequencer[sequence].FirstSent).TotalMilliseconds);

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

                    // Kill the packet
                    _sendSequencer[sequence] = new PendingOutgoingPacket()
                    {
                        Alive    = false,
                        Sequence = sequence
                    };
                }

                for (ushort i = sequence; _sendSequencer[i].Alive; i++)
                {
                    _incomingLowestAckedSequence = i;
                }
            }
        }
Exemplo n.º 4
0
        public HeapMemory CreateOutgoingMessage(ArraySegment <byte> payload, out bool dealloc)
        {
            // Increment the sequence number
            _lastOutboundSequenceNumber++;

            // Allocate the memory
            HeapMemory memory = MemoryManager.Alloc((uint)payload.Count + 4);

            // Write headers
            memory.Buffer[0] = HeaderPacker.Pack((byte)MessageType.Data, false);
            memory.Buffer[1] = channelId;

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

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

            // Add the memory to pending
            _sendSequencer[_lastOutboundSequenceNumber] = new PendingOutgoingPacket()
            {
                Alive     = true,
                Sequence  = _lastOutboundSequenceNumber,
                Attempts  = 1,
                LastSent  = DateTime.Now,
                FirstSent = DateTime.Now,
                Memory    = memory
            };

            // Tell the caller NOT to dealloc the memory, the channel needs it for resend purposes.
            dealloc = false;

            return(memory);
        }
Exemplo n.º 5
0
        public void InternalUpdate()
        {
            lock (_lock)
            {
                if (_lastOutgoingPacket.Alive)
                {
                    if (_lastOutgoingPacket.Attempts > config.ReliabilityMaxResendAttempts)
                    {
                        // If they don't ack the message, disconnect them
                        connection.Disconnect(false);
                        return;
                    }
                    else if ((DateTime.Now - _lastOutgoingPacket.LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier)
                    {
                        _lastOutgoingPacket = new PendingOutgoingPacket()
                        {
                            Alive     = true,
                            Attempts  = (ushort)(_lastOutgoingPacket.Attempts + 1),
                            LastSent  = DateTime.Now,
                            FirstSent = _lastOutgoingPacket.FirstSent,
                            Memory    = _lastOutgoingPacket.Memory,
                            Sequence  = _lastOutgoingPacket.Sequence
                        };

                        connection.SendRaw(new ArraySegment <byte>(_lastOutgoingPacket.Memory.Buffer, (int)_lastOutgoingPacket.Memory.VirtualOffset, (int)_lastOutgoingPacket.Memory.VirtualCount), false, 4);

                        connection.OutgoingResentPackets++;
                    }
                }
            }
        }
Exemplo n.º 6
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));

            lock (_lock)
            {
                if (_lastOutgoingPacket.Alive && _lastOutgoingPacket.Sequence == sequence)
                {
                    // Add statistics
                    connection.OutgoingConfirmedPackets++;

                    // Dealloc the memory held by the last packet
                    _lastOutgoingPacket.DeAlloc(memoryManager);

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

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

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

                    // Kill the packet
                    _lastOutgoingPacket = new PendingOutgoingPacket()
                    {
                        Alive    = false,
                        Sequence = sequence
                    };

                    _incomingLowestAckedSequence = sequence;
                }
            }
        }
Exemplo n.º 7
0
        internal ReliableOrderedChannel(byte channelId, Connection connection, SocketConfig config, MemoryManager memoryManager)
        {
            this.channelId     = channelId;
            this.connection    = connection;
            this.config        = config;
            this.memoryManager = memoryManager;

            _lastOutgoingPacket = new PendingOutgoingPacket()
            {
                Alive     = false,
                Attempts  = 0,
                FirstSent = DateTime.MinValue,
                LastSent  = DateTime.MinValue,
                Memory    = null,
                Sequence  = 0
            };

            _lastAckTimes = new SlidingWindow <DateTime>(config.ReliableAckFlowWindowSize, true, sizeof(ushort));
        }
Exemplo n.º 8
0
        public void Reset()
        {
            lock (_lock)
            {
                // Clear all incoming states
                _incomingLowestAckedSequence = 0;

                // Clear all outgoing states
                _lastOutboundSequenceNumber = 0;

                // Reset the outgoing packet
                _lastOutgoingPacket = new PendingOutgoingPacket()
                {
                    Alive     = false,
                    Attempts  = 0,
                    FirstSent = DateTime.MinValue,
                    LastSent  = DateTime.MinValue,
                    Memory    = null,
                    Sequence  = 0
                };
            }
        }
Exemplo n.º 9
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 (_lock)
            {
                if (_sendSequencer[sequence].Alive && _sendSequencer[sequence].Fragments.VirtualCount > fragment && ((PendingOutgoingFragment)_sendSequencer[sequence].Fragments.Pointers[fragment]).Alive)
                {
                    // Add statistics
                    connection.OutgoingConfirmedPackets++;

                    // Dealloc the memory held by the sequencer for the packet
                    ((PendingOutgoingFragment)_sendSequencer[sequence].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((DateTime.Now - ((PendingOutgoingFragment)_sendSequencer[sequence].Fragments.Pointers[fragment]).FirstSent).TotalMilliseconds);

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

                    // Kill the fragment packet
                    _sendSequencer[sequence].Fragments.Pointers[fragment] = new PendingOutgoingFragment()
                    {
                        Alive    = false,
                        Sequence = sequence
                    };

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

                    if (!hasAllocatedAndAliveFragments)
                    {
                        // Dealloc the wrapper packet
                        _sendSequencer[sequence].DeAlloc(memoryManager);

                        // Kill the wrapper packet
                        _sendSequencer[sequence] = new PendingOutgoingPacket()
                        {
                            Alive = false
                        };
                    }
                }

                for (ushort i = sequence; _sendSequencer[i].Alive && _sendSequencer[i].AllFragmentsAlive; i++)
                {
                    _incomingLowestAckedSequence = i;
                }
            }
        }
Exemplo n.º 10
0
        public HeapPointers CreateOutgoingMessage(ArraySegment <byte> payload, out byte headerSize, out bool dealloc)
        {
            // Calculate the amount of fragments required
            int fragmentsRequired = (payload.Count + (connection.MTU - 1)) / connection.MTU;

            if (fragmentsRequired > config.MaxFragments)
            {
                if (Logging.CurrentLogLevel <= LogLevel.Error)
                {
                    Logging.LogError("Tried to create message that was too large. [Size=" + payload.Count + "] [FragmentsRequired=" + fragmentsRequired + "] [Config.MaxFragments=" + config.MaxFragments + "]");
                }
                dealloc    = false;
                headerSize = 0;
                return(null);
            }

            lock (_lock)
            {
                PendingOutgoingPacket unsafeOutgoing = _sendSequencer.GetUnsafe(_lastOutboundSequenceNumber + 1, out bool isSafe);

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

                    connection.Disconnect(false);

                    dealloc    = false;
                    headerSize = 0;
                    return(null);
                }

                // Increment the sequence number
                _lastOutboundSequenceNumber++;

                // Set header size
                headerSize = 6;

                // Alloc array
                HeapPointers memoryParts = memoryManager.AllocHeapPointers((uint)fragmentsRequired);

                int position = 0;

                for (ushort i = 0; i < fragmentsRequired; i++)
                {
                    // Calculate message size
                    int messageSize = Math.Min(connection.MTU, payload.Count - position);

                    // Allocate memory for each fragment
                    memoryParts.Pointers[memoryParts.VirtualOffset + i] = memoryManager.AllocHeapMemory((uint)(messageSize + 6));

                    // Write headers
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[0] = HeaderPacker.Pack((byte)MessageType.Data, false);
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[1] = channelId;

                    // Write the sequence
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[2] = (byte)_lastOutboundSequenceNumber;
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[3] = (byte)(_lastOutboundSequenceNumber >> 8);

                    // Write the fragment
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[4] = (byte)(i & 32767);
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[5] = (byte)(((i & 32767) >> 8) | (byte)(i == fragmentsRequired - 1 ? 128 : 0));

                    // Write the payload
                    Buffer.BlockCopy(payload.Array, payload.Offset + position, ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer, 6, messageSize);

                    // Increase the position
                    position += messageSize;
                }

                // Tell the caller NOT to dealloc the memory, the channel needs it for resend purposes.
                dealloc = false;

                // Alloc outgoing fragment structs
                HeapPointers outgoingFragments = memoryManager.AllocHeapPointers((uint)fragmentsRequired);

                for (int i = 0; i < fragmentsRequired; i++)
                {
                    // Add the memory to the outgoing sequencer array
                    outgoingFragments.Pointers[outgoingFragments.VirtualOffset + i] = new PendingOutgoingFragment()
                    {
                        Alive     = true,
                        Attempts  = 1,
                        LastSent  = DateTime.Now,
                        FirstSent = DateTime.Now,
                        Sequence  = _lastOutboundSequenceNumber,
                        Memory    = ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i])
                    };
                }

                // Add the memory to the outgoing sequencer
                _sendSequencer[_lastOutboundSequenceNumber] = new PendingOutgoingPacket()
                {
                    Alive     = true,
                    Fragments = outgoingFragments
                };

                return(memoryParts);
            }
        }
Exemplo n.º 11
0
        public HeapPointers CreateOutgoingMessage(ArraySegment <byte> payload, out byte headerSize, out bool dealloc)
        {
            if (payload.Count > connection.MTU)
            {
                if (Logging.CurrentLogLevel <= LogLevel.Error)
                {
                    Logging.LogError("Tried to send message that was too large. Use a fragmented channel instead. [Size=" + payload.Count + "] [MaxMessageSize=" + config.MaxFragments + "]");
                }
                dealloc    = false;
                headerSize = 0;
                return(null);
            }

            lock (_lock)
            {
                PendingOutgoingPacket unsafeOutgoing = _sendSequencer.GetUnsafe(_lastOutboundSequenceNumber + 1, out bool isSafe);

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

                    connection.Disconnect(false);

                    dealloc    = false;
                    headerSize = 0;
                    return(null);
                }

                // Increment the sequence number
                _lastOutboundSequenceNumber++;

                // Set header size
                headerSize = 4;

                // Allocate the memory
                HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count + 4);

                // Write headers
                memory.Buffer[0] = HeaderPacker.Pack((byte)MessageType.Data, false);
                memory.Buffer[1] = channelId;

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

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

                // Add the memory to pending
                _sendSequencer[_lastOutboundSequenceNumber] = new PendingOutgoingPacket()
                {
                    Alive     = true,
                    Sequence  = _lastOutboundSequenceNumber,
                    Attempts  = 1,
                    LastSent  = DateTime.Now,
                    FirstSent = DateTime.Now,
                    Memory    = memory
                };

                // Tell the caller NOT to dealloc the memory, the channel needs it for resend purposes.
                dealloc = false;

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

                // Point the first pointer to the memory
                pointers.Pointers[pointers.VirtualOffset] = memory;

                return(pointers);
            }
        }