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 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); }
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)); // 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; // Set the headerBytes headerBytes = 4; 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."); } hasMore = false; return(null); } lock (_lock) { if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || (_receiveSequencer[sequence].Alive && _receiveSequencer[sequence].IsComplete) || (_receiveSequencer[sequence].Alive && _receiveSequencer[sequence].Fragments != null && _receiveSequencer[sequence].Fragments.VirtualCount > fragment && _receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment] != null && !((HeapMemory)_receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment]).isDead)) { // We have already acked this message. Ack again connection.IncomingDuplicatePackets++; connection.IncomingDuplicateUserBytes += (ulong)payload.Count - 2; connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2; SendAckEncoded(sequence, encodedFragment); hasMore = false; return(null); } else { // This is a packet after the last. One that is not yet completed 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) { // If this is the first fragment we ever get, index the data. // TODO: Alloc more size and just expand later in the pointer array HeapPointers fragmentPointers = memoryManager.AllocHeapPointers((uint)fragment + 1); _receiveSequencer[sequence] = new PendingIncomingPacket() { Alive = true, Fragments = fragmentPointers, Sequence = sequence, Size = isFinal ? (ushort?)(fragment + 1) : null }; } 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 (_receiveSequencer[sequence].Fragments.Pointers.Length - _receiveSequencer[sequence].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(_receiveSequencer[sequence].Fragments.Pointers, newPointers.Pointers, _receiveSequencer[sequence].Fragments.Pointers.Length); // Return the memory for the old memoryManager.DeAlloc(_receiveSequencer[sequence].Fragments); // Update the index _receiveSequencer[sequence] = new PendingIncomingPacket() { Fragments = newPointers, Alive = _receiveSequencer[sequence].Alive, Sequence = _receiveSequencer[sequence].Sequence, Size = isFinal ? (ushort?)(fragment + 1) : _receiveSequencer[sequence].Size }; } // We might also have to expand the virtual count if (_receiveSequencer[sequence].Fragments.VirtualCount <= fragment) { // Update the new virtual count _receiveSequencer[sequence].Fragments.VirtualCount = (uint)fragment + 1; // Update the struct to set the size if it has changed (TODO: Check if needed) _receiveSequencer[sequence] = new PendingIncomingPacket() { Fragments = _receiveSequencer[sequence].Fragments, Alive = _receiveSequencer[sequence].Alive, Sequence = _receiveSequencer[sequence].Sequence, Size = isFinal ? (ushort?)(fragment + 1) : _receiveSequencer[sequence].Size }; } } if (_receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment] == null || ((HeapMemory)_receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment]).isDead) { // 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 _receiveSequencer[sequence].Fragments.Pointers[_receiveSequencer[sequence].Fragments.VirtualOffset + fragment] = memory; } // Send ack SendAckEncoded(sequence, encodedFragment); // Sequenced never returns the original memory. Thus we need to return null and tell the caller to Poll instead. hasMore = _receiveSequencer[_incomingLowestAckedSequence + 1].Alive && _receiveSequencer[_incomingLowestAckedSequence + 1].IsComplete; return(null); } } }
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); } }