public void InternalUpdate(out bool timeout) { lock (_sendLock) { for (ushort i = (ushort)(_outgoingLowestAckedSequence + 1); SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) < 0; i++) { if (_sendSequencer.TryGet(i, out PendingOutgoingPacket value)) { if ((NetTime.Now - value.LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier && (NetTime.Now - value.LastSent).TotalMilliseconds > config.ReliabilityMinPacketResendDelay) { if (value.Attempts >= config.ReliabilityMaxResendAttempts) { // If they don't ack the message, disconnect them timeout = true; return; } _sendSequencer.Update(i, new PendingOutgoingPacket() { Attempts = (ushort)(value.Attempts + 1), LastSent = NetTime.Now, FirstSent = value.FirstSent, Memory = value.Memory, NotificationKey = value.NotificationKey }); connection.SendInternal(new ArraySegment <byte>(value.Memory.Buffer, (int)value.Memory.VirtualOffset, (int)value.Memory.VirtualCount), false); } } } } timeout = false; }
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); } } }