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); }
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); }
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"); } }
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(); } }
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); } }
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)); } }
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)); }
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 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); } }
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); } }
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); } }
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); }
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); } }
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); } }
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); } }
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); }
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); }
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); }
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); } }
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(); } }
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); } }
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); }
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); }
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 + "]"); } }
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); }
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(); } }
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(); } }