public void HandleAck(ArraySegment <byte> payload) { // Read the sequence number ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8)); lock (_sendLock) { if (_lastOutgoingPacket != null && _lastOutgoingPacket.Value.Sequence == sequence) { // Notify the user that we got an ack ChannelRouter.HandlePacketAckedByRemote(connection, channelId, _lastOutgoingPacket.Value.NotificationKey); // Dealloc the memory held by the last packet _lastOutgoingPacket.Value.DeAlloc(memoryManager); // TODO: Remove roundtripping from channeled packets and make specific ping-pong packets // Get the roundtrp ulong roundtrip = (ulong)Math.Round((NetTime.Now - _lastOutgoingPacket.Value.FirstSent).TotalMilliseconds); // Report to the connection connection.AddRoundtripSample(roundtrip); // Kill the packet _lastOutgoingPacket = null; } } }
private void HandleAck(ushort sequence) { lock (_sendLock) { if (_sendSequencer.TryGet(sequence, out PendingOutgoingPacket value)) { // Notify the user about the ack ChannelRouter.HandlePacketAckedByRemote(connection, channelId, value.NotificationKey); // Dealloc the memory held by the sequencer memoryManager.DeAlloc(value.Memory); // TODO: Remove roundtripping from channeled packets and make specific ping-pong packets // Get the roundtrp ulong roundtrip = (ulong)Math.Round((NetTime.Now - value.FirstSent).TotalMilliseconds); // Report to the connection connection.AddRoundtripSample(roundtrip); // Kill the packet _sendSequencer.Remove(sequence); if (sequence == (ushort)(_outgoingLowestAckedSequence + 1)) { // This was the next one. _outgoingLowestAckedSequence++; } } // Loop from the lowest ack we got for (ushort i = _outgoingLowestAckedSequence; !_sendSequencer.Contains(i) && SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) <= 0; i++) { _outgoingLowestAckedSequence = i; } // Check if we can start draining pending pool while (_pendingSends.Count > 0 && _sendSequencer.CanSet((ushort)(_lastOutgoingSequence + 1))) { // Dequeue the pending PendingSend pending = _pendingSends.Dequeue(); // Sequence it CreateOutgoingMessageInternal(new ArraySegment <byte>(pending.Memory.Buffer, (int)pending.Memory.VirtualOffset, (int)pending.Memory.VirtualCount), pending.NoMerge, pending.NotificationKey); // Dealloc memoryManager.DeAlloc(pending.Memory); } } }
public void HandleAck(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; lock (_sendLock) { if (_sendSequencer.TryGet(sequence, out PendingOutgoingPacketFragmented value) && value.Fragments.VirtualCount > fragment && value.Fragments.Pointers[fragment] != null) { // Dealloc the memory held by the sequencer for the packet ((PendingOutgoingFragment)value.Fragments.Pointers[fragment]).DeAlloc(memoryManager); // TODO: Remove roundtripping from channeled packets and make specific ping-pong packets // Get the roundtrp ulong roundtrip = (ulong)Math.Round((NetTime.Now - ((PendingOutgoingFragment)value.Fragments.Pointers[fragment]).FirstSent).TotalMilliseconds); // Report to the connection connection.AddRoundtripSample(roundtrip); // Kill the fragment packet value.Fragments.Pointers[fragment] = null; bool hasAllocatedAndAliveFragments = false; for (int i = 0; i < value.Fragments.VirtualCount; i++) { if (value.Fragments.Pointers[i] != null) { hasAllocatedAndAliveFragments = true; break; } } if (!hasAllocatedAndAliveFragments) { // Notify user that the packet was acked ChannelRouter.HandlePacketAckedByRemote(connection, channelId, value.NotificationKey); // Dealloc the wrapper packet value.DeAlloc(memoryManager); // Kill the wrapper packet _sendSequencer.Remove(sequence); if (sequence == (ushort)(_outgoingLowestAckedSequence + 1)) { // This was the next one. _outgoingLowestAckedSequence++; } } } // Loop from the lowest ack we got for (ushort i = _outgoingLowestAckedSequence; !_sendSequencer.TryGet(i, out value) && SequencingUtils.Distance(i, _lastOutgoingSequence, sizeof(ushort)) <= 0; i++) { _outgoingLowestAckedSequence = i; } // Check if we can start draining pending pool while (_pendingSends.Count > 0 && _sendSequencer.CanSet((ushort)(_lastOutgoingSequence + 1))) { // Dequeue the pending PendingSend pending = _pendingSends.Dequeue(); // Sequence it CreateOutgoingMessageInternal(new ArraySegment <byte>(pending.Memory.Buffer, (int)pending.Memory.VirtualOffset, (int)pending.Memory.VirtualCount), pending.NoMerge, pending.NotificationKey); // Dealloc memoryManager.DeAlloc(pending.Memory); } } }