예제 #1
0
        internal void HandleMTURequest(uint size)
        {
            // This does not access anything shared. We thus dont need to lock the state. If the state is raced or outdated its no harm done.
            // TODO: Remove lock

            _stateLock.EnterReadLock();

            try
            {
                if (State == ConnectionState.Connected)
                {
                    // Alloc memory for response
                    HeapMemory memory = MemoryManager.AllocHeapMemory(size);

                    // Write the header
                    memory.Buffer[0] = HeaderPacker.Pack(MessageType.MTUResponse);

                    // Send the response
                    SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

                    // Dealloc the memory
                    MemoryManager.DeAlloc(memory);
                }
            }
            finally
            {
                _stateLock.ExitReadLock();
            }
        }
        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);

                // 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);

                // Send ack
                connection.SendInternal(new ArraySegment <byte>(ackMemory.Buffer, 0, 4), false);

                // Return memory
                memoryManager.DeAlloc(ackMemory);
            }
        }
예제 #3
0
        internal void SendHail()
        {
            HailStatus.Attempts++;
            HailStatus.LastAttempt = NetTime.Now;

            // Packet size
            int size = 2 + (byte)Config.ChannelTypes.Length;

            // Allocate memory
            HeapMemory memory = MemoryManager.AllocHeapMemory((uint)size);

            // Write the header
            memory.Buffer[0] = HeaderPacker.Pack(MessageType.Hail);

            // Write the amount of channels
            memory.Buffer[1] = (byte)Config.ChannelTypes.Length;

            // Write the channel types
            for (byte i = 0; i < (byte)Config.ChannelTypes.Length; i++)
            {
                memory.Buffer[2 + i] = ChannelTypeUtils.ToByte(Config.ChannelTypes[i]);
            }

            // Send the response
            SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

            // Release memory
            MemoryManager.DeAlloc(memory);

            // Print Debug
            if (Logging.CurrentLogLevel <= LogLevel.Debug)
            {
                Logging.LogInfo("Client " + EndPoint + " was sent a hail");
            }
        }
예제 #4
0
        internal void SendChallengeRequest()
        {
            // Set resend values
            HandshakeResendAttempts++;
            HandshakeLastSendTime = NetTime.Now;

            // Packet size
            uint size = 1 + sizeof(ulong) + 1;

            // Allocate memory
            HeapMemory memory = MemoryManager.AllocHeapMemory(size);

            // Write the header
            memory.Buffer[0] = HeaderPacker.Pack(MessageType.ChallengeRequest);

            // Write connection challenge
            for (byte i = 0; i < sizeof(ulong); i++)
            {
                memory.Buffer[1 + i] = ((byte)(ConnectionChallenge >> (i * 8)));
            }

            // Write the challenge difficulty
            memory.Buffer[1 + sizeof(ulong)] = (byte)ChallengeDifficulty;

            // Send the challenge
            SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

            // Release memory
            MemoryManager.DeAlloc(memory);

            if (Logging.CurrentLogLevel <= LogLevel.Debug)
            {
                Logging.LogInfo("Client " + EndPoint + " was sent a challenge of difficulty " + ChallengeDifficulty);
            }
        }
예제 #5
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);
        }
예제 #6
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);

                // 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);

                // Send ack
                connection.SendRaw(new ArraySegment <byte>(ackMemory.Buffer, 0, 4), false, 4);

                // Return memory
                memoryManager.DeAlloc(ackMemory);
            }
        }
        public void CreateOutgoingMessage(ArraySegment <byte> payload, bool noMerge, ulong notificationKey)
        {
            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 + "]");
                }
                return;
            }

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

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

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

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

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

            // Send the message to the router. Tell the router to dealloc the memory as the channel no longer needs it.
            ChannelRouter.SendMessage(pointers, true, connection, noMerge, memoryManager);
        }
        public void CreateOutgoingMessage(ArraySegment <byte> payload, bool noMerge, ulong notificationKey)
        {
            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 + "]");
                }
                return;
            }

            lock (_sendLock)
            {
                // Increment the sequence number
                _lastOutgoingSequence++;

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

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

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

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

                if (_lastOutgoingPacket != null)
                {
                    // Dealloc the last packet
                    _lastOutgoingPacket.Value.DeAlloc(memoryManager);
                }

                // Add the memory to pending
                _lastOutgoingPacket = new PendingOutgoingPacketSequence()
                {
                    Sequence        = _lastOutgoingSequence,
                    Attempts        = 1,
                    LastSent        = NetTime.Now,
                    FirstSent       = NetTime.Now,
                    Memory          = memory,
                    NotificationKey = notificationKey
                };

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

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

                // Send the message to the router. Tell the router to NOT dealloc the memory as the channel needs it for resend purposes.
                ChannelRouter.SendMessage(pointers, false, connection, noMerge, memoryManager);
            }
        }
예제 #9
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);
            }
        }
예제 #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);
            }
        }
예제 #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)
            {
                // 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);

                // Tell the caller to deallc the memory
                dealloc = true;

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

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

                return(pointers);
            }
        }
예제 #12
0
        internal HeapMemory CreateOutgoingHeartbeatMessage()
        {
            // Increment the sequence number
            _lastOutboundSequenceNumber++;

            // Allocate the memory
            HeapMemory memory = MemoryManager.Alloc(3);

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

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

            return(memory);
        }
예제 #13
0
        public HeapMemory CreateOutgoingMessage(ArraySegment <byte> payload, out bool dealloc)
        {
            // Allocate the memory
            HeapMemory memory = MemoryManager.Alloc((uint)payload.Count + 2);

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

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

            // Tell the caller to deallc the memory
            dealloc = true;

            return(memory);
        }
예제 #14
0
        private void SendAck(ushort sequence)
        {
            // Alloc ack memory
            HeapMemory ackMemory = MemoryManager.Alloc(4);

            // 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);

            // Send ack
            connection.SendRaw(new ArraySegment <byte>(ackMemory.Buffer, 0, 4), false);

            // Return memory
            MemoryManager.DeAlloc(ackMemory);
        }
예제 #15
0
        internal void SendHailConfirmed()
        {
            // Allocate memory
            HeapMemory memory = MemoryManager.AllocHeapMemory(1);

            // Write the header
            memory.Buffer[0] = HeaderPacker.Pack(MessageType.HailConfirmed);

            // Send confirmation
            SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

            // Release memory
            MemoryManager.DeAlloc(memory);

            if (Logging.CurrentLogLevel <= LogLevel.Debug)
            {
                Logging.LogInfo("Hail confirmation sent to " + EndPoint);
            }
        }
예제 #16
0
        private void RunPathMTU()
        {
            _stateLock.EnterReadLock();

            try
            {
                if (State == ConnectionState.Connected && MTU < Config.MaximumMTU && MTUStatus.Attempts < Config.MaxMTUAttempts && (NetTime.Now - MTUStatus.LastAttempt).TotalMilliseconds > Config.MTUAttemptDelay)
                {
                    int attemptedMtu = (int)(MTU * Config.MTUGrowthFactor);

                    if (attemptedMtu > Config.MaximumMTU)
                    {
                        attemptedMtu = Config.MaximumMTU;
                    }

                    if (attemptedMtu < Config.MinimumMTU)
                    {
                        attemptedMtu = Config.MinimumMTU;
                    }

                    MTUStatus.Attempts++;
                    MTUStatus.LastAttempt = NetTime.Now;

                    // Allocate memory
                    HeapMemory memory = MemoryManager.AllocHeapMemory((uint)attemptedMtu);

                    // Set the header
                    memory.Buffer[0] = HeaderPacker.Pack(MessageType.MTURequest);

                    // Send the request
                    SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

                    // Dealloc the memory
                    MemoryManager.DeAlloc(memory);
                }
            }
            finally
            {
                _stateLock.ExitReadLock();
            }
        }
예제 #17
0
        private void SendAck(ushort sequence, ushort fragment, bool isFinal)
        {
            // Alloc ack memory
            HeapMemory ackMemory = memoryManager.AllocHeapMemory(4);

            // 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);

            // Write fragment
            ackMemory.Buffer[4] = (byte)(fragment & 32767);
            ackMemory.Buffer[5] = (byte)(((byte)((fragment & 32767) >> 8)) | (byte)(isFinal ? 128 : 0));

            // Send ack
            connection.SendInternal(new ArraySegment <byte>(ackMemory.Buffer, 0, 6), false);

            // Return memory
            memoryManager.DeAlloc(ackMemory);
        }
예제 #18
0
        private void SendAckEncoded(ushort sequence, ushort encodedFragment)
        {
            // Alloc ack memory
            HeapMemory ackMemory = memoryManager.AllocHeapMemory(4);

            // 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);

            // Write fragment
            ackMemory.Buffer[4] = (byte)encodedFragment;
            ackMemory.Buffer[5] = (byte)(encodedFragment >> 8);

            // Send ack
            connection.SendInternal(new ArraySegment <byte>(ackMemory.Buffer, 0, 6), false);

            // Return memory
            memoryManager.DeAlloc(ackMemory);
        }
예제 #19
0
        internal void SendChallengeResponse()
        {
            // Set resend values
            HandshakeResendAttempts++;
            HandshakeLastSendTime = NetTime.Now;

            // Calculate the minimum size we can fit the packet in
            int minSize = 1 + sizeof(ulong);

            // Calculate the actual size with respect to amplification padding
            int size = Math.Max(minSize, (int)Config.AmplificationPreventionHandshakePadding);

            // Allocate memory
            HeapMemory memory = MemoryManager.AllocHeapMemory((uint)size);

            // Write the header
            memory.Buffer[0] = HeaderPacker.Pack(MessageType.ChallengeResponse);

            // Write the challenge response
            for (byte i = 0; i < sizeof(ulong); i++)
            {
                memory.Buffer[1 + i] = ((byte)(ChallengeAnswer >> (i * 8)));
            }

            // Send the challenge response
            SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

            // Release memory
            MemoryManager.DeAlloc(memory);

            // Print debug
            if (Logging.CurrentLogLevel <= LogLevel.Debug)
            {
                Logging.LogInfo("Server " + EndPoint + " challenge of difficulty " + ChallengeDifficulty + " was solved. Answer was sent. [CollidedValue=" + ChallengeAnswer + "]");
            }
        }
예제 #20
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);

            // Tell the caller to deallc the memory
            dealloc = true;

            return(memory);
        }
예제 #21
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);
            }
        }
예제 #22
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);
            }
        }
예제 #23
0
        private void CreateOutgoingMessageInternal(ArraySegment <byte> payload, bool noMerge, ulong notificationKey)
        {
            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 + "]");
                }
                return;
            }

            if (!_sendSequencer.CanSet((ushort)(_lastOutgoingSequence + 1)))
            {
                if (Logging.CurrentLogLevel <= LogLevel.Warning)
                {
                    Logging.LogWarning("Outgoing packet window is exhausted. Expect delays");
                }

                // Alloc memory
                HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count);

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

                // Enqueue it
                _pendingSends.Enqueue(new PendingSend()
                {
                    Memory          = memory,
                    NoMerge         = noMerge,
                    NotificationKey = notificationKey
                });
            }
            else
            {
                // Increment the sequence number
                _lastOutgoingSequence++;

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

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

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

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

                // Add the memory to pending
                _sendSequencer.Set(_lastOutgoingSequence, new PendingOutgoingPacket()
                {
                    Attempts        = 1,
                    LastSent        = NetTime.Now,
                    FirstSent       = NetTime.Now,
                    Memory          = memory,
                    NotificationKey = notificationKey
                });

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

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

                // Send the message to the router. Tell the router to NOT dealloc the memory as the channel needs it for resend purposes.
                ChannelRouter.SendMessage(pointers, false, connection, noMerge, memoryManager);
            }
        }
예제 #24
0
        internal void DisconnectInternal(bool sendMessage, bool timeout)
        {
#if ALLOW_CONNECTION_STUB
            if (IsStub)
            {
                // NOOP
                return;
            }
#endif

            // TODO: Could be just a normal write lock. The chance of it not being a write in the end is small.
            _stateLock.EnterUpgradeableReadLock();

            try
            {
                if (State == ConnectionState.Connected && sendMessage && !timeout)
                {
                    // Send disconnect message

                    // Allocate memory
                    HeapMemory memory = MemoryManager.AllocHeapMemory(1);

                    // Write disconnect header
                    memory.Buffer[0] = HeaderPacker.Pack(MessageType.Disconnect);

                    // Send disconnect message
                    SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

                    // Release memory
                    MemoryManager.DeAlloc(memory);
                }

                if (State != ConnectionState.Disconnected)
                {
                    _stateLock.EnterWriteLock();

                    try
                    {
                        // Set the state to disconnected
                        State = ConnectionState.Disconnected;

                        // Release all memory
                        Release();
                    }
                    finally
                    {
                        _stateLock.ExitWriteLock();
                    }

                    // Remove from global lookup
                    Socket.RemoveConnection(this);

                    // Send disconnect to userspace
                    Socket.PublishEvent(new NetworkEvent()
                    {
                        Connection        = this,
                        Socket            = Socket,
                        Type              = timeout ? NetworkEventType.Timeout : NetworkEventType.Disconnect,
                        AllowUserRecycle  = false,
                        ChannelId         = 0,
                        Data              = new ArraySegment <byte>(),
                        InternalMemory    = null,
                        SocketReceiveTime = NetTime.Now,
                        MemoryManager     = MemoryManager,
                        EndPoint          = EndPoint
                    });
                }
            }
            finally
            {
                _stateLock.ExitUpgradeableReadLock();
            }
        }
예제 #25
0
        private void CheckConnectionResends()
        {
            _stateLock.EnterReadLock();

            try
            {
                switch (State)
                {
                case ConnectionState.RequestingConnection:
                {
                    if ((!Config.TimeBasedConnectionChallenge || PreConnectionChallengeSolved) && (NetTime.Now - HandshakeLastSendTime).TotalMilliseconds > Config.ConnectionRequestMinResendDelay && HandshakeResendAttempts <= Config.MaxConnectionRequestResends)
                    {
                        HandshakeResendAttempts++;
                        HandshakeLastSendTime = NetTime.Now;

                        // Calculate the minimum size we can fit the packet in
                        int minSize = 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (Config.TimeBasedConnectionChallenge ? sizeof(ulong) * 3 : 0);

                        // Calculate the actual size with respect to amplification padding
                        int size = Math.Max(minSize, (int)Config.AmplificationPreventionHandshakePadding);

                        // Allocate memory
                        HeapMemory memory = MemoryManager.AllocHeapMemory((uint)size);

                        // Write the header
                        memory.Buffer[0] = HeaderPacker.Pack((byte)MessageType.ConnectionRequest);

                        // Copy the identification token
                        Buffer.BlockCopy(Constants.RUFFLES_PROTOCOL_IDENTIFICATION, 0, memory.Buffer, 1, Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length);

                        if (Config.TimeBasedConnectionChallenge)
                        {
                            // Write the response unix time
                            for (byte x = 0; x < sizeof(ulong); x++)
                            {
                                memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + x] = ((byte)(PreConnectionChallengeTimestamp >> (x * 8)));
                            }

                            // Write counter
                            for (byte x = 0; x < sizeof(ulong); x++)
                            {
                                memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + x] = ((byte)(PreConnectionChallengeCounter >> (x * 8)));
                            }

                            // Write IV
                            for (byte x = 0; x < sizeof(ulong); x++)
                            {
                                memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + x] = ((byte)(PreConnectionChallengeIV >> (x * 8)));
                            }

                            // Print debug
                            if (Logging.CurrentLogLevel <= LogLevel.Debug)
                            {
                                Logging.LogInfo("Resending ConnectionRequest with challenge [Counter=" + PreConnectionChallengeCounter + "] [IV=" + PreConnectionChallengeIV + "] [Time=" + PreConnectionChallengeTimestamp + "] [Hash=" + HashProvider.GetStableHash64(PreConnectionChallengeTimestamp, PreConnectionChallengeCounter, PreConnectionChallengeIV) + "]");
                            }
                        }
                        else
                        {
                            // Print debug
                            if (Logging.CurrentLogLevel <= LogLevel.Debug)
                            {
                                Logging.LogInfo("Resending ConnectionRequest");
                            }
                        }

                        SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

                        // Release memory
                        MemoryManager.DeAlloc(memory);
                    }
                }
                break;

                case ConnectionState.RequestingChallenge:
                {
                    if ((NetTime.Now - HandshakeLastSendTime).TotalMilliseconds > Config.HandshakeResendDelay && HandshakeResendAttempts <= Config.MaxHandshakeResends)
                    {
                        // Resend challenge request
                        SendChallengeRequest();
                    }
                }
                break;

                case ConnectionState.SolvingChallenge:
                {
                    if ((NetTime.Now - HandshakeLastSendTime).TotalMilliseconds > Config.HandshakeResendDelay && HandshakeResendAttempts <= Config.MaxHandshakeResends)
                    {
                        // Resend response
                        SendChallengeResponse();
                    }
                }
                break;

                case ConnectionState.Connected:
                {
                    if (!HailStatus.HasAcked && (NetTime.Now - HailStatus.LastAttempt).TotalMilliseconds > Config.HandshakeResendDelay && HailStatus.Attempts <= Config.MaxHandshakeResends)
                    {
                        // Resend hail
                        SendHail();
                    }
                }
                break;
                }
            }
            finally
            {
                _stateLock.ExitReadLock();
            }
        }
예제 #26
0
        private void CreateOutgoingMessageInternal(ArraySegment <byte> payload, bool noMerge, ulong notificationKey)
        {
            // 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 + "]");
                }
                return;
            }

            if (!_sendSequencer.CanSet((ushort)(_lastOutgoingSequence + 1)))
            {
                if (Logging.CurrentLogLevel <= LogLevel.Warning)
                {
                    Logging.LogWarning("Outgoing packet window is exhausted. Expect delays");
                }

                // Alloc memory
                HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count);

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

                // Enqueue it
                _pendingSends.Enqueue(new PendingSend()
                {
                    Memory          = memory,
                    NoMerge         = noMerge,
                    NotificationKey = notificationKey
                });
            }
            else
            {
                // Increment the sequence number
                _lastOutgoingSequence++;

                // 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(MessageType.Data);
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[1] = channelId;

                    // Write the sequence
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[2] = (byte)_lastOutgoingSequence;
                    ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i]).Buffer[3] = (byte)(_lastOutgoingSequence >> 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;
                }

                // 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()
                    {
                        Attempts  = 1,
                        LastSent  = NetTime.Now,
                        FirstSent = NetTime.Now,
                        Memory    = ((HeapMemory)memoryParts.Pointers[memoryParts.VirtualOffset + i])
                    };
                }

                // Add the memory to the outgoing sequencer
                _sendSequencer.Set(_lastOutgoingSequence, new PendingOutgoingPacketFragmented()
                {
                    Fragments       = outgoingFragments,
                    NotificationKey = notificationKey
                });

                // Send the message to the router. Tell the router to NOT dealloc the memory as the channel needs it for resend purposes.
                ChannelRouter.SendMessage(memoryParts, false, connection, noMerge, memoryManager);
            }
        }