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)); lock (_receiveLock) { if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0) { // Set the new sequence _incomingLowestAckedSequence = sequence; // Alloc pointers HeapPointers pointers = memoryManager.AllocHeapPointers(1); // Alloc wrapper pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); return(pointers); } /* else * Logging.LogInfo("Dropped packet in UnreliableOrdered channel..."); */ return(null); } }
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 (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || ((_receiveSequencer.TryGet(sequence, out PendingIncomingPacketFragmented value) && (value.IsComplete || (value.Fragments != null && 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); }
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) { // We have already acked this message. Ack again SendAck(sequence); return(null); } else { // This is a future packet // Add to sequencer _incomingLowestAckedSequence = sequence; // Send ack SendAck(sequence); // Alloc pointers HeapPointers pointers = memoryManager.AllocHeapPointers(1); // Alloc a memory wrapper pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); return(pointers); } } }
public void InternalUpdate() { long distance = SequencingUtils.Distance(_lastOutboundSequenceNumber, _incomingLowestAckedSequence, sizeof(ushort)); for (ushort i = _incomingLowestAckedSequence; i < _incomingLowestAckedSequence + distance; i++) { if (_sendSequencer[i].Alive) { if (_sendSequencer[i].Attempts > config.ReliabilityMaxResendAttempts) { // If they don't ack the message, disconnect them connection.Disconnect(false); } else if ((DateTime.Now - _sendSequencer[i].LastSent).TotalMilliseconds > connection.Roundtrip * config.ReliabilityResendRoundtripMultiplier) { _sendSequencer[i] = new PendingOutgoingPacket() { Alive = true, Attempts = (ushort)(_sendSequencer[i].Attempts + 1), LastSent = DateTime.Now, FirstSent = _sendSequencer[i].FirstSent, Memory = _sendSequencer[i].Memory, Sequence = i }; connection.SendRaw(new ArraySegment <byte>(_sendSequencer[i].Memory.Buffer, (int)_sendSequencer[i].Memory.VirtualOffset, (int)_sendSequencer[i].Memory.VirtualCount), 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)); lock (_receiveLock) { if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0 || _incomingAckedSequences.Contains(sequence)) { // We have already acked this message. Ack again SendAck(sequence); return(null); } else if (sequence == _incomingLowestAckedSequence + 1) { // This is the "next" packet do { // Remove previous _incomingAckedSequences.Remove(_incomingLowestAckedSequence); _incomingLowestAckedSequence++; }while (_incomingAckedSequences.Contains((ushort)(_incomingLowestAckedSequence + 1))); // Ack the new message SendAck(sequence); // Alloc pointers HeapPointers pointers = memoryManager.AllocHeapPointers(1); // Alloc a memory wrapper pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); return(pointers); } else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_incomingAckedSequences.Contains(sequence)) { // This is a future packet // Add to sequencer _incomingAckedSequences.Add(sequence); // Ack the new message SendAck(sequence); // Alloc pointers HeapPointers pointers = memoryManager.AllocHeapPointers(1); // Alloc a memory wrapper pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); return(pointers); } return(null); } }
public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore) { // Reliable has one message in equal no more than one out. hasMore = false; // 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 || _incomingAckedPackets.Contains(sequence)) { // We have already acked this message. Ack again connection.IncomingDuplicatePackets++; connection.IncomingDuplicateUserBytes += (ulong)payload.Count - 2; connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2; SendAck(sequence); return(null); } else if (sequence == _incomingLowestAckedSequence + 1) { // This is the "next" packet do { // Remove previous _incomingAckedPackets.Remove(_incomingLowestAckedSequence); _incomingLowestAckedSequence++; }while (_incomingAckedPackets.Contains((ushort)(_incomingLowestAckedSequence + 1))); // Ack the new message SendAck(sequence); return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); } else if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_incomingAckedPackets.Contains(sequence)) { // This is a future packet // Add to sequencer _incomingAckedPackets.Add(sequence); SendAck(sequence); return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); } return(null); } }
internal override void ResendPoll() { long distance = SequencingUtils.Distance(_lastOutboundSequenceNumber, _lowestAckedMessage, sizeof(ushort)); for (ushort i = _lowestAckedMessage; i < _lowestAckedMessage + distance; i++) { if (_sendSequencer.HasMessage(i) && (DateTime.Now - _sendSequencer.Peek(i).LastSent).TotalMilliseconds > Constants.RESEND_DELAY) { _sendSequencer.Peek(i).LastSentBy.SendPacket(_sendSequencer.Peek(i), _sendSequencer.Peek(i).LastSentTo); } } }
public override ChanneledPacket HandleIncomingMessagePoll(byte[] buffer, int length, out bool hasMore) { hasMore = false; UnreliableSequencedPacket packet = new UnreliableSequencedPacket(); packet.Read(buffer, length); long distance = SequencingUtils.Distance(packet.Sequence, _lastReceivedSequenceNumber, sizeof(ushort)); if (distance > 0) { // This packet is a future packet _lastReceivedSequenceNumber = packet.Sequence; _receiveSequencer.Push(packet); } // Set the ack if (_sendSequencer.HasMessage(packet.AckSequence) && _sendSequencer.Peek(packet.AckSequence).ExplicitResponse != ExplicitResponseState.Ack) { packet.ExplicitResponse = ExplicitResponseState.Ack; OnMessageAck(packet.AckSequence); } // Resolve their acks & nacks from mask for (int i = 0; i < Constants.ACK_MASK_BITS; i++) { if (_sendSequencer.HasMessage(packet.AckSequence - i)) { ExplicitResponseState newState = (packet.AckMask & (1UL << i)) != 0 ? ExplicitResponseState.Ack : ExplicitResponseState.Nack; ExplicitResponseState currentState = _sendSequencer.Peek(packet.AckSequence - i).ExplicitResponse; if (currentState != newState && currentState != ExplicitResponseState.Ack) { if (newState == ExplicitResponseState.Ack) { OnMessageAck(packet.AckSequence - i); } if (newState == ExplicitResponseState.Nack) { OnMessageNack(packet.AckSequence - i); } } _sendSequencer.Peek(packet.AckSequence - i).ExplicitResponse = newState; } } return(distance > 0 ? packet : null); }
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 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); } }
public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out bool hasMore) { // UnreliableSequenced has one message in equal no more than one out. hasMore = false; // 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) { // Set the new sequence _incomingLowestAckedSequence = sequence; return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); } return(null); }
public override ChanneledPacket HandleIncomingMessagePoll(byte[] buffer, int size, out bool hasMore) { // Reliable has one message in equal no more than one out. hasMore = false; ReliablePacket packet = new ReliablePacket(); packet.Read(buffer, size); if (packet.Sequence <= _incomingLowestAckedSequence || _incomingAckedPackets.ContainsKey(packet.Sequence)) { // They didnt get our ack. // TODO: Send ack return(null); } else if (packet.Sequence == _incomingLowestAckedSequence + 1) { // This is the "next" packet do { // Remove previous _incomingAckedPackets.Remove(_incomingLowestAckedSequence); _incomingLowestAckedSequence++; }while (packet.Sequence == _incomingLowestAckedSequence + 1); // TODO: Send ack return(packet); } else if (SequencingUtils.Distance(packet.Sequence, _incomingLowestAckedSequence, sizeof(ushort)) > 0 && !_incomingAckedPackets.ContainsKey(packet.Sequence)) { // This is a future packet _incomingAckedPackets.Add(packet.Sequence, packet); // TODO: Send ack return(packet); } return(null); }
public HeapPointers HandleIncomingMessagePoll(ArraySegment <byte> payload) { // -> Sorting happens in the ConcurrentCircularQueue when messages are Enqueued // // Read the sequence number ushort sequence = (ushort)(payload.Array[payload.Offset] | (ushort)(payload.Array[payload.Offset + 1] << 8)); lock (_receiveLock) { if (_incomingAckedPackets.Contains(sequence)) { // We have already received this message. Ignore it. return(null); } /* if (SequencingUtils.Distance(sequence, _incomingLowestAckedSequence, sizeof(ushort)) <= 0) * { * if (SequencingUtils.Distance(sequence, _lastPollSequence, sizeof(ushort)) > 0) * { * Logging.LogInfo("Skipping dropping packet since it's newer than _lastPollSequence (" + _lastPollSequence + ") | _incomingLowestAckedSequence: " + _incomingLowestAckedSequence + " | currentSequence: " + sequence); * } * } */ if (SequencingUtils.Distance(sequence, _lastPollSequence, sizeof(ushort)) > 0) // ! We're using _lastPollSequence instead of _incomingLowestAckedSequence to not drop old packets if we're still waiting for them to be polled by the game/MLAPI, which can still be sorted properly { // Set the new sequence _incomingLowestAckedSequence = sequence; _incomingAckedPackets.Set(sequence, true); // Alloc pointers HeapPointers pointers = memoryManager.AllocHeapPointers(1); // Alloc wrapper pointers.Pointers[0] = memoryManager.AllocMemoryWrapper(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); return(pointers); } return(null); } }
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 PendingOutgoingPacketFragmented value)) { for (int j = 0; j < value.Fragments.VirtualCount; j++) { if (value.Fragments.Pointers[j] != null) { PendingOutgoingFragment fragment = (PendingOutgoingFragment)value.Fragments.Pointers[j]; if ((NetTime.Now - fragment.LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier && (NetTime.Now - fragment.LastSent).TotalMilliseconds > config.ReliabilityMinPacketResendDelay) { if (fragment.Attempts >= config.ReliabilityMaxResendAttempts) { // If they don't ack the message, disconnect them timeout = true; return; } fragment = new PendingOutgoingFragment() { Attempts = (ushort)(fragment.Attempts + 1), LastSent = NetTime.Now, FirstSent = fragment.FirstSent, Memory = fragment.Memory }; value.Fragments.Pointers[j] = fragment; connection.SendInternal(new ArraySegment <byte>(fragment.Memory.Buffer, (int)fragment.Memory.VirtualOffset, (int)fragment.Memory.VirtualCount), false); } } } } } } timeout = false; }
public void InternalUpdate() { lock (_lock) { long distance = SequencingUtils.Distance(_lastOutboundSequenceNumber, _incomingLowestAckedSequence, sizeof(ushort)); for (ushort i = _incomingLowestAckedSequence; i < _incomingLowestAckedSequence + distance; i++) { if (_sendSequencer[i].Alive) { for (int j = 0; j < _sendSequencer[i].Fragments.VirtualCount; j++) { if (_sendSequencer[i].Fragments.Pointers[j] != null && ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Alive) { if (((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Attempts > config.ReliabilityMaxResendAttempts) { // If they don't ack the message, disconnect them connection.Disconnect(false); return; } else if ((DateTime.Now - ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).LastSent).TotalMilliseconds > connection.SmoothRoundtrip * config.ReliabilityResendRoundtripMultiplier) { _sendSequencer[i].Fragments.Pointers[j] = new PendingOutgoingFragment() { Alive = true, Attempts = (ushort)(((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Attempts + 1), LastSent = DateTime.Now, FirstSent = ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).FirstSent, Memory = ((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory, Sequence = i }; connection.SendRaw(new ArraySegment <byte>(((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory.Buffer, (int)((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory.VirtualOffset, (int)((PendingOutgoingFragment)_sendSequencer[i].Fragments.Pointers[j]).Memory.VirtualCount), false, 6); connection.OutgoingResentPackets++; } } } } } } }
public T this[int index] { get { int arrayIndex = NumberUtils.WrapMod(index, _array.Length); if (_indexes[arrayIndex] == index) { return(_array[arrayIndex]); } else { return(default(T)); } } set { if (_resetOld) { long distance = SequencingUtils.Distance((ulong)index, _lastHighestSequence, _wrapSize); if (distance > 0) { for (int i = 1; i < distance; i++) { int resetArrayIndex = NumberUtils.WrapMod(((int)_lastHighestSequence + index + i), _array.Length); _indexes[resetArrayIndex] = ((int)_lastHighestSequence + index + i); _array[resetArrayIndex] = default(T); } _lastHighestSequence = (ulong)index; } } int arrayIndex = NumberUtils.WrapMod(index, _array.Length); _indexes[arrayIndex] = index; _array[arrayIndex] = value; } }
public ArraySegment <byte>?HandleIncomingMessagePoll(ArraySegment <byte> payload, out byte headerBytes, out bool hasMore) { // ReliableStateUpdate has one message in equal no more than one out. hasMore = false; // 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) { // We have already acked this message. Ack again connection.IncomingDuplicatePackets++; connection.IncomingDuplicateUserBytes += (ulong)payload.Count - 2; connection.IncomingDuplicateTotalBytes += (ulong)payload.Count + 2; SendAck(sequence); return(null); } else { // This is a future packet // Add to sequencer _incomingLowestAckedSequence = sequence; SendAck(sequence); return(new ArraySegment <byte>(payload.Array, payload.Offset + 2, payload.Count - 2)); } } }
public bool TryEnqueue(T element, bool sortBySequence = false, int sequence = -1000) { // Cache writeHead and try to assign in a loop instead of pre incrementing writeHead in order to safe against buffer wraparounds while (true) { int positionWrite = _writeHead; int arrayIndexWrite = NumberUtils.WrapMod(positionWrite, _array.Length); if (_indexes[arrayIndexWrite] == _writeHead && Interlocked.CompareExchange(ref _writeHead, positionWrite + 1, positionWrite) == positionWrite) { if (sequence != -1000 && sortBySequence && Count > 0) { // Go from positionRead to positionWrite and if an element is bigger than sequence, that's where we will insert and update all the next ones to the right index bool done = false; /* string s1 = ""; * string s2 = ""; */ lock ("sortLock") { for (int k = _readHead; k <= _writeHead; k++) { int arrayIndex = NumberUtils.WrapMod(k, _array.Length); //string s0 = _sequences[arrayIndex] + " "; if (_sequences[arrayIndex] != -1000 && SequencingUtils.Distance((ulong)_sequences[arrayIndex], (ulong)sequence, sizeof(ushort)) > 0) { if (k != _writeHead) { for (int i = _writeHead + 1; i > k; i--) { int previousAI = NumberUtils.WrapMod(i - 1, _array.Length); int aI = NumberUtils.WrapMod(i, _array.Length); /* if (i != _writeHead + 1) * s1 = _sequences[aI] + " " + s1; * s2 = _sequences[previousAI] + " " + s2; */ _array[aI] = _array[previousAI]; Thread.MemoryBarrier(); _indexes[aI] = _indexes[previousAI] + 1; _sequences[aI] = _sequences[previousAI]; } _array[arrayIndex] = element; Thread.MemoryBarrier(); _sequences[arrayIndex] = sequence; /* Logging.LogInfo("Needs sorting: ... " + s0 + "| " + s1 + "*" + sequence + " (" + _readHead + " - " + _writeHead + ")"); * Logging.LogInfo("----- Sorted: ... *" + sequence + " | " + s2 + " (" + _readHead + " - " + _writeHead + ")"); */ done = true; break; } } } if (!done) { //Logging.LogInfo("- No sorting: " + s0 + s + sequence); _array[arrayIndexWrite] = element; Thread.MemoryBarrier(); _indexes[arrayIndexWrite] = positionWrite + 1; _sequences[arrayIndexWrite] = sequence; } } } else { _array[arrayIndexWrite] = element; Thread.MemoryBarrier(); _indexes[arrayIndexWrite] = positionWrite + 1; if (sortBySequence) { _sequences[arrayIndexWrite] = sequence; } } return(true); } else if (_indexes[arrayIndexWrite] < positionWrite) { // Overflow, it cannot be assigned as a forward enqueue did not occur return(false); } } }
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); } }
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); } } }
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); } } }
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); } } }
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 bool this[T key] { get { if (_indexLookup.ContainsKey(key)) { int index = _indexLookup[key]; int arrayIndex = NumberUtils.WrapMod(index, _indexes.Length); if (_indexes[arrayIndex] == index) { return(true); } } return(false); } set { ushort index; if (_indexLookup.ContainsKey(key)) { index = _indexLookup[key]; } else { index = _indexCounter; _indexCounter++; } if (_resetOld) { long distance = SequencingUtils.Distance(index, _lastHighestSequence, _wrapSize); if (distance > 0) { for (ushort i = 1; i < distance; i++) { int resetArrayIndex = NumberUtils.WrapMod((_lastHighestSequence + index + i), _indexes.Length); _indexes[resetArrayIndex] = (ushort)(_lastHighestSequence + index + i); if (_indexLookup.ContainsKey(_array[resetArrayIndex])) { _indexLookup.Remove(_array[resetArrayIndex]); } _array[resetArrayIndex] = default(T); } _lastHighestSequence = index; } } int arrayIndex = NumberUtils.WrapMod(index, _indexes.Length); if (_indexLookup.ContainsKey(_array[arrayIndex])) { _indexLookup.Remove(_array[arrayIndex]); } if (value) { _indexLookup.Add(key, index); } _indexes[arrayIndex] = index; _array[arrayIndex] = key; } }
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); } }