Пример #1
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);
            }
        }
Пример #2
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();
            }
        }
Пример #3
0
        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
                _lastOutboundSequenceNumber++;

                // 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)_lastOutboundSequenceNumber;
                memory.Buffer[3] = (byte)(_lastOutboundSequenceNumber >> 8);

                // Copy the payload
                Buffer.BlockCopy(payload.Array, payload.Offset, memory.Buffer, 4, 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);
            }
        }
Пример #4
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);
            }

            // Set header size
            headerSize = 2;

            // Allocate the memory
            HeapMemory memory = memoryManager.AllocHeapMemory((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;

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

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

            return(pointers);
        }
Пример #5
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 + "]");
            }
        }
Пример #6
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();
            }
        }
Пример #7
0
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));
            // Read the raw fragment data
            ushort encodedFragment = (ushort)(payload.Array[payload.Offset + 2] | (ushort)(payload.Array[payload.Offset + 3] << 8));
            // The fragmentId is the last 15 least significant bits
            ushort fragment = (ushort)(encodedFragment & 32767);
            // IsFinal is the most significant bit
            bool isFinal = (ushort)((encodedFragment & 32768) >> 15) == 1;

            if (fragment >= config.MaxFragments)
            {
                if (Logging.CurrentLogLevel <= LogLevel.Error)
                {
                    Logging.LogError("FragmentId was too large. [FragmentId=" + fragment + "] [Config.MaxFragments=" + config.MaxFragments + "]. The fragment was silently dropped, expect a timeout.");
                }
                return(null);
            }

            lock (_receiveLock)
            {
                // If the sequence is older than the last one we sent to user OR the packet is already acked OR the sequence is alive and its complete OR (the sequence is alive AND the fragments is alloced AND the alloced fragment count is larger than the fragment (I.E, the fragment is actually alloced) AND the fragment is not null AND the fragment is not dead))
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 ||
                    (_incomingAckedSequences.Contains(sequence)) ||
                    (_receiveSequencer.TryGet(sequence, out PendingIncomingPacketFragmented value) && (value.IsComplete || (value.Fragments.VirtualCount > fragment && value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] != null))))
                {
                    // We have already acked this message. Ack again

                    SendAckEncoded(sequence, encodedFragment);

                    return(null);
                }
                else
                {
                    // This is a packet after the last. One that is not yet completed

                    if (!_receiveSequencer.CanUpdateOrSet(sequence))
                    {
                        // If we cant update or set, that means the window is full and we are not in the window.

                        if (Logging.CurrentLogLevel <= LogLevel.Warning)
                        {
                            Logging.LogWarning("Incoming packet window is exhausted. Expect delays");
                        }
                        return(null);
                    }

                    if (!_receiveSequencer.TryGet(sequence, out value))
                    {
                        // If this is the first fragment we ever get, index the data.

                        HeapPointers fragmentPointers = memoryManager.AllocHeapPointers((uint)fragment + 1);

                        value = new PendingIncomingPacketFragmented()
                        {
                            Fragments = fragmentPointers,
                            Size      = isFinal ? (ushort?)(fragment + 1) : null
                        };

                        _receiveSequencer.Set(sequence, value);
                    }
                    else
                    {
                        // If the first fragment we got was fragment 1 / 500. The fragments array will only be of size 128. We need to potentially resize it
                        if (value.Fragments.Pointers.Length - value.Fragments.VirtualOffset <= fragment)
                        {
                            // We need to expand the fragments array.

                            // Alloc new array
                            HeapPointers newPointers = memoryManager.AllocHeapPointers((uint)fragment + 1);

                            // Copy old values
                            Array.Copy(value.Fragments.Pointers, newPointers.Pointers, value.Fragments.Pointers.Length);

                            // Return the memory for the old
                            memoryManager.DeAlloc(value.Fragments);

                            // Update the index
                            value = new PendingIncomingPacketFragmented()
                            {
                                Fragments = newPointers,
                                Size      = isFinal ? (ushort?)(fragment + 1) : value.Size
                            };

                            _receiveSequencer.Update(sequence, value);
                        }

                        // We might also have to expand the virtual count
                        if (value.Fragments.VirtualCount <= fragment)
                        {
                            // Update the new virtual count
                            value.Fragments.VirtualCount = (uint)fragment + 1;

                            // Update the struct to set the size if it has changed (TODO: Check if needed)
                            value = new PendingIncomingPacketFragmented()
                            {
                                Fragments = value.Fragments,
                                Size      = isFinal ? (ushort?)(fragment + 1) : value.Size
                            };

                            _receiveSequencer.Update(sequence, value);
                        }
                    }

                    // If the fragment is null OR the fragment is DEAD
                    if (value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] == null)
                    {
                        // Alloc some memory for the fragment
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 4);

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

                        // Add fragment to index
                        value.Fragments.Pointers[value.Fragments.VirtualOffset + fragment] = memory;
                    }

                    // Send ack
                    SendAckEncoded(sequence, encodedFragment);

                    // If this sequence just completed. Return the memory
                    if (value.IsComplete)
                    {
                        if (sequence == (ushort)(_incomingLowestAckedSequence + 1))
                        {
                            // This is the next packet.

                            do
                            {
                                // Remove previous
                                _incomingAckedSequences.Remove(_incomingLowestAckedSequence);

                                _incomingLowestAckedSequence++;
                            }while (_incomingAckedSequences.Contains((ushort)(_incomingLowestAckedSequence + 1)));
                        }
                        else
                        {
                            // This is a future one
                            _incomingAckedSequences.Add(sequence);
                        }

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

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

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

                        // Kill
                        _receiveSequencer.Remove(sequence);

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

                        // Alloc a memory wrapper
                        pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(memory);

                        return(pointers);
                    }

                    return(null);
                }
            }
        }
Пример #8
0
        internal static void HandleIncomingMessage(ArraySegment <byte> payload, Connection connection, SocketConfig config, MemoryManager memoryManager)
        {
            // This is where all data packets arrive after passing the connection handling.

            byte channelId = payload.Array[payload.Offset];

            if (channelId < 0 || channelId >= connection.Channels.Length)
            {
                // ChannelId out of range
                if (Logging.CurrentLogLevel <= LogLevel.Warning)
                {
                    Logging.LogWarning("Got message on channel out of range. [ChannelId=" + channelId + "]");
                }
                return;
            }

            IChannel channel = connection.Channels[channelId];

            if (channel != null)
            {
                HeapPointers incomingPointers = channel.HandleIncomingMessagePoll(new ArraySegment <byte>(payload.Array, payload.Offset + 1, payload.Count - 1));

                if (incomingPointers != null)
                {
                    ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));                     // TODO: This is already calculated inside HandleIncomingMessagePoll, we could just get it from there instead of doing this again...

                    // There is new packets
                    for (int i = 0; i < incomingPointers.VirtualCount; i++)
                    {
                        MemoryWrapper wrapper = (MemoryWrapper)incomingPointers.Pointers[i];

                        HeapMemory memory = null;

                        if (wrapper.AllocatedMemory != null)
                        {
                            memory = wrapper.AllocatedMemory;
                        }

                        if (wrapper.DirectMemory != null)
                        {
                            // Alloc memory
                            memory = memoryManager.AllocHeapMemory((uint)wrapper.DirectMemory.Value.Count);

                            // Copy payload to borrowed memory
                            Buffer.BlockCopy(wrapper.DirectMemory.Value.Array, wrapper.DirectMemory.Value.Offset, memory.Buffer, 0, wrapper.DirectMemory.Value.Count);
                        }

                        if (memory != null)
                        {
                            // Send to userspace
                            connection.Socket.PublishEvent(new NetworkEvent()
                            {
                                Connection        = connection,
                                Socket            = connection.Socket,
                                Type              = NetworkEventType.Data,
                                AllowUserRecycle  = true,
                                Data              = new ArraySegment <byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount),
                                InternalMemory    = memory,
                                SocketReceiveTime = NetTime.Now,
                                ChannelId         = channelId,
                                Sequence          = sequence,
                                MemoryManager     = memoryManager,
                                EndPoint          = connection.EndPoint
                            });
                        }

                        // Dealloc the wrapper
                        memoryManager.DeAlloc(wrapper);
                    }

                    // Dealloc the pointers
                    memoryManager.DeAlloc(incomingPointers);
                }
            }
            else
            {
                if (Logging.CurrentLogLevel <= LogLevel.Warning)
                {
                    Logging.LogWarning("Receive message failed because the channel is not assigned");
                }
            }
        }
Пример #9
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);
            }
        }
        public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            lock (_receiveLock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _receiveSequencer.Contains(sequence))
                {
                    // We have already acked this message. Ack again

                    SendAck(sequence);

                    return(null);
                }
                else if (sequence == (ushort)(_incomingLowestAckedSequence + 1))
                {
                    // This is the packet right after

                    _incomingLowestAckedSequence++;

                    // Send ack
                    SendAck(sequence);

                    uint additionalPackets = 0;

                    // Count all the additional sequential packets that are ready
                    for (int i = 1; (_receiveSequencer.TryGet((ushort)(_incomingLowestAckedSequence + i), out PendingIncomingPacket value)); i++)
                    {
                        additionalPackets++;
                    }

                    // Allocate pointers (alloc size 1, we might need more)
                    HeapPointers pointers = memoryManager.AllocHeapPointers(1 + additionalPackets);

                    // Point the first pointer to the memory that is known.
                    pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));

                    for (int i = 0; _receiveSequencer.TryGet((ushort)(_incomingLowestAckedSequence + 1), out PendingIncomingPacket value); i++)
                    {
                        // Update lowest incoming
                        ++_incomingLowestAckedSequence;

                        // Set the memory
                        pointers.Pointers[1 + i] = memoryManager.AllocMemoryWrapper(value.Memory);

                        // Kill
                        _receiveSequencer.Remove(_incomingLowestAckedSequence);
                    }

                    return(pointers);
                }
                else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0)
                {
                    // Future packet

                    if (!_receiveSequencer.CanUpdateOrSet(sequence))
                    {
                        // If we cant update or set, that means the window is full and we are not in the window.

                        if (Logging.CurrentLogLevel <= LogLevel.Warning)
                        {
                            Logging.LogWarning("Incoming packet window is exhausted. Expect delays");
                        }
                        return(null);
                    }

                    if (!_receiveSequencer.Contains(sequence))
                    {
                        // Alloc payload plus header memory
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 2);

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

                        // Add to sequencer
                        _receiveSequencer.Set(sequence, new PendingIncomingPacket()
                        {
                            Memory = memory
                        });

                        // Send ack
                        SendAck(sequence);
                    }
                }

                return(null);
            }
        }
Пример #11
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();
            }
        }
Пример #12
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);
            }
        }
Пример #13
0
        internal static void HandleIncomingMessage(ArraySegment <byte> payload, Connection connection, SocketConfig activeConfig, MemoryManager memoryManager)
        {
            // This is where all data packets arrive after passing the connection handling.

            byte channelId = payload.Array[payload.Offset];

            if (channelId < 0 || channelId >= connection.Channels.Length)
            {
                // ChannelId out of range
                if (Logging.CurrentLogLevel <= LogLevel.Warning)
                {
                    Logging.LogWarning("Got message on channel out of range. [ChannelId=" + channelId + "]");
                }
                return;
            }

            ArraySegment <byte>?incomingMessage = connection.Channels[channelId].HandleIncomingMessagePoll(new ArraySegment <byte>(payload.Array, payload.Offset + 1, payload.Count - 1), out byte headerBytes, out bool hasMore);

            connection.IncomingUserBytes += (ulong)payload.Count - headerBytes;

            if (incomingMessage != null)
            {
                // Alloc memory that can be borrowed to userspace
                HeapMemory memory = memoryManager.AllocHeapMemory((uint)incomingMessage.Value.Count);

                // Copy payload to borrowed memory
                Buffer.BlockCopy(incomingMessage.Value.Array, incomingMessage.Value.Offset, memory.Buffer, 0, incomingMessage.Value.Count);

                // Send to userspace
                connection.Socket.PublishEvent(new NetworkEvent()
                {
                    Connection        = connection,
                    Socket            = connection.Socket,
                    Type              = NetworkEventType.Data,
                    AllowUserRecycle  = true,
                    Data              = new ArraySegment <byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount),
                    InternalMemory    = memory,
                    SocketReceiveTime = DateTime.Now,
                    ChannelId         = channelId,
                    MemoryManager     = memoryManager
                });
            }

            if (hasMore)
            {
                HeapMemory messageMemory = null;

                do
                {
                    messageMemory = connection.Channels[channelId].HandlePoll();

                    if (messageMemory != null)
                    {
                        // Send to userspace
                        connection.Socket.PublishEvent(new NetworkEvent()
                        {
                            Connection        = connection,
                            Socket            = connection.Socket,
                            Type              = NetworkEventType.Data,
                            AllowUserRecycle  = true,
                            Data              = new ArraySegment <byte>(messageMemory.Buffer, (int)messageMemory.VirtualOffset, (int)messageMemory.VirtualCount),
                            InternalMemory    = messageMemory,
                            SocketReceiveTime = DateTime.Now,
                            ChannelId         = channelId,
                            MemoryManager     = memoryManager
                        });
                    }
                }while (messageMemory != null);
            }
        }
Пример #14
0
        public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore)
        {
            // Read the sequence number
            ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8));

            // Set the headerBytes
            headerBytes = 2;

            lock (_lock)
            {
                if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _receiveSequencer[sequence].Alive)
                {
                    // We have already acked this message. Ack again

                    connection.IncomingDuplicatePackets++;
                    connection.IncomingDuplicateUserBytes  += (ulong)payload.Count - 2;
                    connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2;

                    SendAck(sequence);

                    hasMore = false;
                    return(null);
                }
                else if (sequence == _incomingLowestAckedSequence + 1)
                {
                    // This is the packet right after

                    // If the one after is alive, we give set hasMore to true
                    hasMore = _receiveSequencer[_incomingLowestAckedSequence + 2].Alive;

                    _incomingLowestAckedSequence++;

                    // Send ack
                    SendAck(sequence);

                    return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2));
                }
                else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0)
                {
                    // Future packet

                    PendingIncomingPacket unsafeIncoming = _receiveSequencer.GetUnsafe(sequence, out bool isSafe);

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

                        connection.Disconnect(false);

                        hasMore = false;
                        return(null);
                    }
                    else if (!_receiveSequencer[sequence].Alive)
                    {
                        // Alloc payload plus header memory
                        HeapMemory memory = memoryManager.AllocHeapMemory((uint)payload.Count - 2);

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

                        // Add to sequencer
                        _receiveSequencer[sequence] = new PendingIncomingPacket()
                        {
                            Alive    = true,
                            Memory   = memory,
                            Sequence = sequence
                        };

                        // Send ack
                        SendAck(sequence);
                    }
                }

                hasMore = false;
                return(null);
            }
        }