Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
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();
            }
        }
        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);
        }
Ejemplo n.º 4
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");
            }
        }
Ejemplo n.º 5
0
        private void CheckConnectionHeartbeats()
        {
            _stateLock.EnterReadLock();

            try
            {
                if (State == ConnectionState.Connected)
                {
                    if ((NetTime.Now - LastMessageOut).TotalMilliseconds > Config.HeartbeatDelay)
                    {
                        // This client has not been talked to in a long time. Send a heartbeat.

                        // Create sequenced heartbeat packet
                        HeapMemory heartbeatMemory = HeartbeatChannel.CreateOutgoingHeartbeatMessage();

                        // Send heartbeat
                        SendInternal(new ArraySegment <byte>(heartbeatMemory.Buffer, (int)heartbeatMemory.VirtualOffset, (int)heartbeatMemory.VirtualCount), false);

                        // DeAlloc the memory
                        MemoryManager.DeAlloc(heartbeatMemory);
                    }
                }
            }
            finally
            {
                _stateLock.ExitReadLock();
            }
        }
Ejemplo n.º 6
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);
            }
        }
        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);
            }
        }
Ejemplo n.º 8
0
        public void TestOutOfOrderSingleFragment()
        {
            Configuration.SocketConfig config = new Configuration.SocketConfig()
            {
                MinimumMTU = 1050
            };

            MemoryManager memoryManager = new MemoryManager(config);

            Connection clientsConnectionToServer = Connection.Stub(config, memoryManager);
            Connection serversConnectionToClient = Connection.Stub(config, memoryManager);

            ReliableSequencedFragmentedChannel clientChannel = new ReliableSequencedFragmentedChannel(0, clientsConnectionToServer, config, memoryManager);
            ReliableSequencedFragmentedChannel serverChannel = new ReliableSequencedFragmentedChannel(0, serversConnectionToClient, config, memoryManager);

            // Create 3 payloads
            byte[] message1 = BufferHelper.GetRandomBuffer(1024, 0);
            byte[] message2 = BufferHelper.GetRandomBuffer(1024, 1);
            byte[] message3 = BufferHelper.GetRandomBuffer(1024, 2);

            // Sequence all payloads as outgoing
            HeapMemory message1Memory = ((HeapMemory)clientChannel.CreateOutgoingMessage(new ArraySegment <byte>(message1, 0, 1024), out _, out bool dealloc).Pointers[0]);
            HeapMemory message2Memory = ((HeapMemory)clientChannel.CreateOutgoingMessage(new ArraySegment <byte>(message2, 0, 1024), out _, out dealloc).Pointers[0]);
            HeapMemory message3Memory = ((HeapMemory)clientChannel.CreateOutgoingMessage(new ArraySegment <byte>(message3, 0, 1024), out _, out dealloc).Pointers[0]);

            // Consume 1st payload
            ArraySegment <byte>?payload1 = serverChannel.HandleIncomingMessagePoll(new ArraySegment <byte>(message1Memory.Buffer, (int)message1Memory.VirtualOffset + 2, (int)message1Memory.VirtualCount - 2), out _, out bool hasMore1);
            // Consume 3rd payload
            ArraySegment <byte>?payload3 = serverChannel.HandleIncomingMessagePoll(new ArraySegment <byte>(message3Memory.Buffer, (int)message3Memory.VirtualOffset + 2, (int)message3Memory.VirtualCount - 2), out _, out bool hasMore3);
            // Consume 2nd payload
            ArraySegment <byte>?payload2 = serverChannel.HandleIncomingMessagePoll(new ArraySegment <byte>(message2Memory.Buffer, (int)message2Memory.VirtualOffset + 2, (int)message2Memory.VirtualCount - 2), out _, out bool hasMore2);

            Assert.Null(payload1);
            Assert.Null(payload2);
            Assert.Null(payload3);

            Assert.True(hasMore1);
            Assert.True(hasMore2);
            Assert.True(hasMore3);

            HeapMemory poll1 = serverChannel.HandlePoll();
            HeapMemory poll2 = serverChannel.HandlePoll();
            HeapMemory poll3 = serverChannel.HandlePoll();

            Assert.NotNull(poll1);
            Assert.NotNull(poll2);
            Assert.NotNull(poll3);

            {
                Assert.That(BufferHelper.ValidateBufferSizeAndIdentity(poll1, 0, 1024));
            }

            {
                Assert.That(BufferHelper.ValidateBufferSizeAndIdentity(poll2, 1, 1024));
            }

            {
                Assert.That(BufferHelper.ValidateBufferSizeAndIdentity(poll3, 2, 1024));
            }
        }
Ejemplo n.º 9
0
        public void TestSimpleMessageSingleFragment()
        {
            Configuration.SocketConfig config = new Configuration.SocketConfig()
            {
                MinimumMTU = 1050
            };

            MemoryManager memoryManager = new MemoryManager(config);

            Connection clientsConnectionToServer = Connection.Stub(config, memoryManager);
            Connection serversConnectionToClient = Connection.Stub(config, memoryManager);

            ReliableSequencedFragmentedChannel clientChannel = new ReliableSequencedFragmentedChannel(0, clientsConnectionToServer, config, memoryManager);
            ReliableSequencedFragmentedChannel serverChannel = new ReliableSequencedFragmentedChannel(0, serversConnectionToClient, config, memoryManager);

            byte[] message = BufferHelper.GetRandomBuffer(1024, 0);

            HeapMemory          messageMemory = ((HeapMemory)clientChannel.CreateOutgoingMessage(new ArraySegment <byte>(message, 0, 1024), out _, out bool dealloc).Pointers[0]);
            ArraySegment <byte>?payload       = serverChannel.HandleIncomingMessagePoll(new ArraySegment <byte>(messageMemory.Buffer, (int)messageMemory.VirtualOffset + 2, (int)messageMemory.VirtualCount - 2), out _, out bool hasMore);

            Assert.Null(payload);
            Assert.True(hasMore);

            HeapMemory payloadMemory = serverChannel.HandlePoll();

            Assert.NotNull(payloadMemory);

            Assert.That(BufferHelper.ValidateBufferSizeAndIdentity(payloadMemory, 0, 1024));
        }
Ejemplo n.º 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);

                // 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);
            }
        }
Ejemplo n.º 11
0
        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);
            }
        }
Ejemplo n.º 12
0
 public void DeAlloc(MemoryManager memoryManager)
 {
     if (IsAlloced)
     {
         memoryManager.DeAlloc(Memory);
         Memory = null;
     }
 }
        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);
            }
        }
Ejemplo n.º 14
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);
            }
        }
Ejemplo n.º 15
0
        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);
        }
Ejemplo n.º 16
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);
            }
        }
Ejemplo n.º 17
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);
            }
        }
Ejemplo n.º 18
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);
            }
        }
Ejemplo n.º 19
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);
        }
Ejemplo n.º 20
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);
        }
Ejemplo n.º 21
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);
        }
Ejemplo n.º 22
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);
            }
        }
Ejemplo n.º 23
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();
            }
        }
Ejemplo n.º 24
0
        internal static void SendMessage(ArraySegment <byte> payload, Connection connection, byte channelId, bool noDelay)
        {
            if (channelId < 0 || channelId >= connection.Channels.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(channelId), channelId, "ChannelId was out of range");
            }

            IChannel channel = connection.Channels[channelId];

            HeapMemory messageMemory = channel.CreateOutgoingMessage(payload, out bool dealloc);

            if (messageMemory != null)
            {
                connection.SendRaw(new ArraySegment <byte>(messageMemory.Buffer, (int)messageMemory.VirtualOffset, (int)messageMemory.VirtualCount), noDelay);
            }

            if (dealloc)
            {
                // DeAlloc the memory again. This is done for unreliable channels that need the message after the initial send.
                MemoryManager.DeAlloc(messageMemory);
            }
        }
Ejemplo n.º 25
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);
        }
Ejemplo n.º 26
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);
        }
Ejemplo n.º 27
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 + "]");
            }
        }
Ejemplo n.º 28
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);
        }
Ejemplo n.º 29
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();
            }
        }
Ejemplo n.º 30
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();
            }
        }