public void ReceivePacket(byte[] packetData, int bufferLength) { if (bufferLength > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is larger than max packet size"); } if (packetData == null) { throw new InvalidOperationException("Tried to receive null packet!"); } if (bufferLength > packetData.Length) { throw new InvalidOperationException("Buffer length exceeds actual packet length!"); } byte prefixByte = packetData[0]; if ((prefixByte & 1) == 0) { // regular packet ushort sequence; ushort ack; uint ackBits; byte channelID; bool compressed; int packetHeaderBytes = PacketIO.ReadPacketHeader(packetData, 0, bufferLength, out channelID, out sequence, out ack, out ackBits, out compressed); bool isStale; lock (receivedPackets) isStale = !receivedPackets.TestInsert(sequence); if (!isStale && (prefixByte & 0x80) == 0) { if (packetHeaderBytes >= bufferLength) { throw new FormatException($"Buffer too small for packet data! {packetHeaderBytes} packetHeaderBytes > {bufferLength} bufferLength"); } ByteBuffer tempBuffer = ObjPool <ByteBuffer> .Get(); if (compressed) { var decompressedBytes = LZ4Codec.Unwrap(packetData, packetHeaderBytes); tempBuffer.SetSize(decompressedBytes.Length); tempBuffer.BufferCopy(decompressedBytes, 0, 0, decompressedBytes.Length); bufferLength = decompressedBytes.Length + packetHeaderBytes; } else { tempBuffer.SetSize(bufferLength - packetHeaderBytes); tempBuffer.BufferCopy(packetData, packetHeaderBytes, 0, tempBuffer.Length); } // process packet config.ProcessPacketCallback(sequence, tempBuffer.InternalBuffer, tempBuffer.Length); // add to received buffer lock (receivedPackets) { ReceivedPacketData receivedPacketData = receivedPackets.Insert(sequence); if (receivedPacketData == null) { throw new InvalidOperationException("Failed to insert received packet!"); } receivedPacketData.time = this.time; receivedPacketData.packetBytes = (uint)(bufferLength); } ObjPool <ByteBuffer> .Return(tempBuffer); } if (!isStale || (prefixByte & 0x80) != 0) { for (int i = 0; i < 32; i++) { if ((ackBits & 1) != 0) { ushort ack_sequence = (ushort)(ack - i); SentPacketData sentPacketData = sentPackets.Find(ack_sequence); if (sentPacketData != null && !sentPacketData.acked) { sentPacketData.acked = true; if (config.AckPacketCallback != null) { config.AckPacketCallback(ack_sequence); } float rtt = (float)(this.time - sentPacketData.time) * 1000.0f; if ((this.rtt == 0f && rtt > 0f) || Math.Abs(this.rtt - rtt) < 0.00001f) { this.rtt = rtt; } else { this.rtt += (rtt - this.rtt) * config.RTTSmoothFactor; } } } ackBits >>= 1; } } } else { // fragment packet int fragmentID; int numFragments; int fragmentBytes; ushort sequence; ushort ack; uint ackBits; byte fragmentChannelID; bool compressed; int fragmentHeaderBytes = PacketIO.ReadFragmentHeader(packetData, 0, bufferLength, config.MaxFragments, config.FragmentSize, out fragmentID, out numFragments, out fragmentBytes, out sequence, out ack, out ackBits, out fragmentChannelID, out compressed); FragmentReassemblyData reassemblyData = fragmentReassembly.Find(sequence); if (reassemblyData == null) { reassemblyData = fragmentReassembly.Insert(sequence); // failed to insert into buffer (stale) if (reassemblyData == null) { return; } reassemblyData.Sequence = sequence; reassemblyData.Ack = 0; reassemblyData.AckBits = 0; reassemblyData.NumFragmentsReceived = 0; reassemblyData.NumFragmentsTotal = numFragments; reassemblyData.PacketBytes = 0; reassemblyData.PacketDataBuffer.SetSize(0); Array.Clear(reassemblyData.FragmentReceived, 0, reassemblyData.FragmentReceived.Length); } if (numFragments != reassemblyData.NumFragmentsTotal) { return; } if (reassemblyData.FragmentReceived[fragmentID]) { return; } reassemblyData.NumFragmentsReceived++; reassemblyData.FragmentReceived[fragmentID] = true; byte[] tempFragmentData = BufferPool.GetBuffer(2048); Buffer.BlockCopy(packetData, fragmentHeaderBytes, tempFragmentData, 0, bufferLength - fragmentHeaderBytes); reassemblyData.StoreFragmentData(fragmentChannelID, sequence, ack, ackBits, fragmentID, config.FragmentSize, tempFragmentData, bufferLength - fragmentHeaderBytes, compressed); BufferPool.ReturnBuffer(tempFragmentData); if (reassemblyData.NumFragmentsReceived == reassemblyData.NumFragmentsTotal) { // grab internal buffer and pass it to ReceivePacket. Internal buffer will be packet marked as normal packet, so it will go through normal packet path // copy into new buffer to remove preceding offset (used to simplify variable length header handling) ByteBuffer temp = ObjPool <ByteBuffer> .Get(); temp.SetSize(reassemblyData.PacketDataBuffer.Length - reassemblyData.HeaderOffset); Buffer.BlockCopy(reassemblyData.PacketDataBuffer.InternalBuffer, reassemblyData.HeaderOffset, temp.InternalBuffer, 0, temp.Length); // receive packet this.ReceivePacket(temp.InternalBuffer, temp.Length); // return temp buffer ObjPool <ByteBuffer> .Return(temp); // clear reassembly reassemblyData.PacketDataBuffer.SetSize(0); fragmentReassembly.Remove(sequence); } } }
public ushort SendPacket(byte[] packetData, int position, int length, byte channelID) { if (length > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is too large to send, max packet size is " + config.MaxPacketSize + " bytes"); } if (length < 1) { throw new ArgumentOutOfRangeException("Packet is too small; minimum packet size is 1 byte."); } var compressedBuffer = LZ4Codec.Wrap(packetData, position, length); bool compressed = false; int bytesSaved = length - compressedBuffer.Length; if (bytesSaved > 0) { packetData = compressedBuffer; position = 0; length = compressedBuffer.Length; compressed = true; } ushort sequence = this.sequence++; ushort ack; uint ackBits; lock (receivedPackets) receivedPackets.GenerateAckBits(out ack, out ackBits); SentPacketData sentPacketData = sentPackets.Insert(sequence); sentPacketData.time = this.time; sentPacketData.packetBytes = (uint)(config.PacketHeaderSize + length); sentPacketData.acked = false; if (length <= config.FragmentThreshold) { // regular packet byte[] transmitData = BufferPool.GetBuffer(2048); int headerBytes = PacketIO.WritePacketHeader(transmitData, channelID, sequence, ack, ackBits, compressed); int transmitBufferLength = length + headerBytes; Buffer.BlockCopy(packetData, position, transmitData, headerBytes, length); config.TransmitPacketCallback(transmitData, transmitBufferLength); BufferPool.ReturnBuffer(transmitData); } else { // fragmented packet byte[] packetHeader = BufferPool.GetBuffer(Defines.MAX_PACKET_HEADER_BYTES); int packetHeaderBytes = 0; try { packetHeaderBytes = PacketIO.WritePacketHeader(packetHeader, channelID, sequence, ack, ackBits, compressed); } catch { throw; } int numFragments = (length / config.FragmentSize) + ((length % config.FragmentSize) != 0 ? 1 : 0); //int fragmentBufferSize = Defines.FRAGMENT_HEADER_BYTES + Defines.MAX_PACKET_HEADER_BYTES + config.FragmentSize; byte[] fragmentPacketData = BufferPool.GetBuffer(2048); int qpos = 0; byte prefixByte = 1; prefixByte |= (byte)((channelID & 0x03) << 6); for (int fragmentID = 0; fragmentID < numFragments; fragmentID++) { using (var writer = ByteArrayReaderWriter.Get(fragmentPacketData)) { writer.Write(prefixByte); writer.Write(channelID); writer.Write(sequence); writer.Write((byte)fragmentID); writer.Write((byte)(numFragments - 1)); writer.Write(compressed ? (byte)1 : (byte)0); if (fragmentID == 0) { writer.WriteBuffer(packetHeader, 0, packetHeaderBytes); } int bytesToCopy = config.FragmentSize; if (qpos + bytesToCopy > length) { bytesToCopy = length - qpos; } for (int i = 0; i < bytesToCopy; i++) { writer.Write(packetData[position + qpos++]); } int fragmentPacketBytes = (int)writer.WritePosition; config.TransmitPacketCallback(fragmentPacketData, fragmentPacketBytes); } } BufferPool.ReturnBuffer(packetHeader); BufferPool.ReturnBuffer(fragmentPacketData); } return(sequence); }
public void Update(double newTime) { time = newTime; uint num = (uint)(sentPackets.sequence - config.SentPacketBufferSize + 1 + 65535); int num2 = 0; int num3 = config.SentPacketBufferSize / 2; for (int i = 0; i < num3; i++) { ushort num4 = (ushort)(num + i); SentPacketData sentPacketData = sentPackets.Find(num4); if (sentPacketData != null && !sentPacketData.acked) { num2++; } } float num5 = (float)num2 / (float)num3; if (Math.Abs(packetLoss - num5) > 1E-05f) { packetLoss += (num5 - packetLoss) * config.PacketLossSmoothingFactor; } else { packetLoss = num5; } uint num6 = (uint)(sentPackets.sequence - config.SentPacketBufferSize + 1 + 65535); int num7 = 0; double num8 = double.MaxValue; double num9 = 0.0; int num10 = config.SentPacketBufferSize / 2; for (int j = 0; j < num10; j++) { ushort num11 = (ushort)(num6 + j); SentPacketData sentPacketData2 = sentPackets.Find(num11); if (sentPacketData2 != null) { num7 += (int)sentPacketData2.packetBytes; num8 = Math.Min(num8, sentPacketData2.time); num9 = Math.Max(num9, sentPacketData2.time); } } if (num8 != double.MaxValue && num9 != 0.0) { float num12 = (float)num7 / (float)(num9 - num8) * 8f / 1000f; if (Math.Abs(sentBandwidthKBPS - num12) > 1E-05f) { sentBandwidthKBPS += (num12 - sentBandwidthKBPS) * config.BandwidthSmoothingFactor; } else { sentBandwidthKBPS = num12; } } lock (receivedPackets) { uint num13 = (uint)(receivedPackets.sequence - config.ReceivedPacketBufferSize + 1 + 65535); int num14 = 0; double num15 = double.MaxValue; double num16 = 0.0; int num17 = config.ReceivedPacketBufferSize / 2; for (int k = 0; k < num17; k++) { ushort num18 = (ushort)(num13 + k); ReceivedPacketData receivedPacketData = receivedPackets.Find(num18); if (receivedPacketData != null) { num14 += (int)receivedPacketData.packetBytes; num15 = Math.Min(num15, receivedPacketData.time); num16 = Math.Max(num16, receivedPacketData.time); } } if (num15 != double.MaxValue && num16 != 0.0) { float num19 = (float)num14 / (float)(num16 - num15) * 8f / 1000f; if (Math.Abs(receivedBandwidthKBPS - num19) > 1E-05f) { receivedBandwidthKBPS += (num19 - receivedBandwidthKBPS) * config.BandwidthSmoothingFactor; } else { receivedBandwidthKBPS = num19; } } } uint num20 = (uint)(sentPackets.sequence - config.SentPacketBufferSize + 1 + 65535); int num21 = 0; double num22 = double.MaxValue; double num23 = 0.0; int num24 = config.SentPacketBufferSize / 2; for (int l = 0; l < num24; l++) { ushort num25 = (ushort)(num20 + l); SentPacketData sentPacketData3 = sentPackets.Find(num25); if (sentPacketData3 != null && sentPacketData3.acked) { num21 += (int)sentPacketData3.packetBytes; num22 = Math.Min(num22, sentPacketData3.time); num23 = Math.Max(num23, sentPacketData3.time); } } if (num22 != double.MaxValue && num23 != 0.0) { float num26 = (float)num21 / (float)(num23 - num22) * 8f / 1000f; if (Math.Abs(ackedBandwidthKBPS - num26) > 1E-05f) { ackedBandwidthKBPS += (num26 - ackedBandwidthKBPS) * config.BandwidthSmoothingFactor; } else { ackedBandwidthKBPS = num26; } } }
public void ReceivePacket(byte[] packetData, int bufferLength) { if (bufferLength > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is larger than max packet size"); } if (packetData == null) { throw new InvalidOperationException("Tried to receive null packet!"); } if (bufferLength > packetData.Length) { throw new InvalidOperationException("Buffer length exceeds actual packet length!"); } byte b = packetData[0]; if ((b & 1) == 0) { byte channelID; ushort arg; ushort ack; uint ackBits; int num = PacketIO.ReadPacketHeader(packetData, 0, bufferLength, out channelID, out arg, out ack, out ackBits); bool flag; lock (receivedPackets) { flag = !receivedPackets.TestInsert(arg); } if (!flag && (b & 0x80) == 0) { if (num >= bufferLength) { throw new FormatException("Buffer too small for packet data!"); } ByteBuffer byteBuffer = ObjPool <ByteBuffer> .Get(); byteBuffer.SetSize(bufferLength - num); byteBuffer.BufferCopy(packetData, num, 0, byteBuffer.Length); config.ProcessPacketCallback(arg, byteBuffer.InternalBuffer, byteBuffer.Length); lock (receivedPackets) { ReceivedPacketData receivedPacketData = receivedPackets.Insert(arg); if (receivedPacketData == null) { throw new InvalidOperationException("Failed to insert received packet!"); } receivedPacketData.time = time; receivedPacketData.packetBytes = (uint)(config.PacketHeaderSize + bufferLength); } ObjPool <ByteBuffer> .Return(byteBuffer); } if (flag && (b & 0x80) == 0) { return; } for (int i = 0; i < 32; i++) { if ((ackBits & 1) != 0) { ushort obj = (ushort)(ack - i); SentPacketData sentPacketData = sentPackets.Find(obj); if (sentPacketData != null && !sentPacketData.acked) { sentPacketData.acked = true; if (config.AckPacketCallback != null) { config.AckPacketCallback(obj); } float num2 = (float)(time - sentPacketData.time) * 1000f; if ((rtt == 0f && num2 > 0f) || Math.Abs(rtt - num2) < 1E-05f) { rtt = num2; } else { rtt += (num2 - rtt) * config.RTTSmoothFactor; } } } ackBits >>= 1; } return; } int fragmentID; int numFragments; int fragmentBytes; ushort num3; ushort ack2; uint ackBits2; byte channelID2; int num4 = PacketIO.ReadFragmentHeader(packetData, 0, bufferLength, config.MaxFragments, config.FragmentSize, out fragmentID, out numFragments, out fragmentBytes, out num3, out ack2, out ackBits2, out channelID2); FragmentReassemblyData fragmentReassemblyData = fragmentReassembly.Find(num3); if (fragmentReassemblyData == null) { fragmentReassemblyData = fragmentReassembly.Insert(num3); if (fragmentReassemblyData == null) { return; } fragmentReassemblyData.Sequence = num3; fragmentReassemblyData.Ack = 0; fragmentReassemblyData.AckBits = 0u; fragmentReassemblyData.NumFragmentsReceived = 0; fragmentReassemblyData.NumFragmentsTotal = numFragments; fragmentReassemblyData.PacketBytes = 0; Array.Clear(fragmentReassemblyData.FragmentReceived, 0, fragmentReassemblyData.FragmentReceived.Length); } if (numFragments == fragmentReassemblyData.NumFragmentsTotal && !fragmentReassemblyData.FragmentReceived[fragmentID]) { fragmentReassemblyData.NumFragmentsReceived++; fragmentReassemblyData.FragmentReceived[fragmentID] = true; byte[] buffer = BufferPool.GetBuffer(2048); Buffer.BlockCopy(packetData, num4, buffer, 0, bufferLength - num4); fragmentReassemblyData.StoreFragmentData(channelID2, num3, ack2, ackBits2, fragmentID, config.FragmentSize, buffer, bufferLength - num4); BufferPool.ReturnBuffer(buffer); if (fragmentReassemblyData.NumFragmentsReceived == fragmentReassemblyData.NumFragmentsTotal) { ByteBuffer byteBuffer2 = ObjPool <ByteBuffer> .Get(); byteBuffer2.SetSize(fragmentReassemblyData.PacketDataBuffer.Length - fragmentReassemblyData.HeaderOffset); Buffer.BlockCopy(fragmentReassemblyData.PacketDataBuffer.InternalBuffer, fragmentReassemblyData.HeaderOffset, byteBuffer2.InternalBuffer, 0, byteBuffer2.Length); ReceivePacket(byteBuffer2.InternalBuffer, byteBuffer2.Length); ObjPool <ByteBuffer> .Return(byteBuffer2); fragmentReassemblyData.PacketDataBuffer.SetSize(0); fragmentReassembly.Remove(num3); } } }
public ushort SendPacket(byte[] packetData, int length, byte channelID) { if (length > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is too large to send, max packet size is " + config.MaxPacketSize + " bytes"); } ushort num = sequence++; ushort ack; uint ackBits; lock (receivedPackets) { receivedPackets.GenerateAckBits(out ack, out ackBits); } SentPacketData sentPacketData = sentPackets.Insert(num); sentPacketData.time = time; sentPacketData.packetBytes = (uint)(config.PacketHeaderSize + length); sentPacketData.acked = false; if (length <= config.FragmentThreshold) { byte[] buffer = BufferPool.GetBuffer(2048); int num2 = PacketIO.WritePacketHeader(buffer, channelID, num, ack, ackBits); int arg = length + num2; Buffer.BlockCopy(packetData, 0, buffer, num2, length); config.TransmitPacketCallback(buffer, arg); BufferPool.ReturnBuffer(buffer); } else { byte[] buffer2 = BufferPool.GetBuffer(10); int num3 = 0; try { num3 = PacketIO.WritePacketHeader(buffer2, channelID, num, ack, ackBits); } catch { throw; } int num4 = length / config.FragmentSize + ((length % config.FragmentSize != 0) ? 1 : 0); byte[] buffer3 = BufferPool.GetBuffer(2048); int num5 = 0; byte b = 1; b = (byte)(b | (byte)((channelID & 3) << 6)); for (int i = 0; i < num4; i++) { using (ByteArrayReaderWriter byteArrayReaderWriter = ByteArrayReaderWriter.Get(buffer3)) { byteArrayReaderWriter.Write(b); byteArrayReaderWriter.Write(channelID); byteArrayReaderWriter.Write(num); byteArrayReaderWriter.Write((byte)i); byteArrayReaderWriter.Write((byte)(num4 - 1)); if (i == 0) { byteArrayReaderWriter.WriteBuffer(buffer2, num3); } int num6 = config.FragmentSize; if (num5 + num6 > length) { num6 = length - num5; } for (int j = 0; j < num6; j++) { byteArrayReaderWriter.Write(packetData[num5++]); } int arg2 = (int)byteArrayReaderWriter.WritePosition; config.TransmitPacketCallback(buffer3, arg2); } } BufferPool.ReturnBuffer(buffer2); BufferPool.ReturnBuffer(buffer3); } return(num); }
public void ReceivePacket(byte[] packetData, int bufferLength) { if (bufferLength > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is larger than max packet size"); } byte prefixByte = packetData[0]; if ((prefixByte & 1) == 0) { // regular packet ushort sequence; ushort ack; uint ackBits; byte channelID; int packetHeaderBytes = PacketIO.ReadPacketHeader(packetData, 0, bufferLength, out channelID, out sequence, out ack, out ackBits); bool isStale = !receivedPackets.TestInsert(sequence); if (!isStale && (prefixByte & 0x80) == 0) { ByteBuffer tempBuffer = ObjPool <ByteBuffer> .Get(); tempBuffer.SetSize(bufferLength - packetHeaderBytes); tempBuffer.BufferCopy(packetData, packetHeaderBytes, 0, tempBuffer.Length); // process packet config.ProcessPacketCallback(sequence, tempBuffer.InternalBuffer, tempBuffer.Length); // add to received buffer ReceivedPacketData receivedPacketData = receivedPackets.Insert(sequence); receivedPacketData.time = this.time; receivedPacketData.packetBytes = (uint)(config.PacketHeaderSize + bufferLength); ObjPool <ByteBuffer> .Return(tempBuffer); } if (!isStale || (prefixByte & 0x80) != 0) { for (int i = 0; i < 32; i++) { if ((ackBits & 1) != 0) { ushort ack_sequence = (ushort)(ack - i); SentPacketData sentPacketData = sentPackets.Find(ack_sequence); if (sentPacketData != null && !sentPacketData.acked) { sentPacketData.acked = true; if (config.AckPacketCallback != null) { config.AckPacketCallback(ack_sequence); } float rtt = (float)(this.time - sentPacketData.time) * 1000.0f; if ((this.rtt == 0f && rtt > 0f) || Math.Abs(this.rtt - rtt) < 0.00001f) { this.rtt = rtt; } else { this.rtt += (rtt - this.rtt) * config.RTTSmoothFactor; } } } ackBits >>= 1; } } } else { // fragment packet int fragmentID; int numFragments; int fragmentBytes; ushort sequence; ushort ack; uint ackBits; byte fragmentChannelID; int fragmentHeaderBytes = PacketIO.ReadFragmentHeader(packetData, 0, bufferLength, config.MaxFragments, config.FragmentSize, out fragmentID, out numFragments, out fragmentBytes, out sequence, out ack, out ackBits, out fragmentChannelID); FragmentReassemblyData reassemblyData = fragmentReassembly.Find(sequence); if (reassemblyData == null) { reassemblyData = fragmentReassembly.Insert(sequence); // failed to insert into buffer (stale) if (reassemblyData == null) { return; } reassemblyData.Sequence = sequence; reassemblyData.Ack = 0; reassemblyData.AckBits = 0; reassemblyData.NumFragmentsReceived = 0; reassemblyData.NumFragmentsTotal = numFragments; reassemblyData.PacketBytes = 0; Array.Clear(reassemblyData.FragmentReceived, 0, reassemblyData.FragmentReceived.Length); } if (numFragments != reassemblyData.NumFragmentsTotal) { return; } if (reassemblyData.FragmentReceived[fragmentID]) { return; } reassemblyData.NumFragmentsReceived++; reassemblyData.FragmentReceived[fragmentID] = true; byte[] tempFragmentData = BufferPool.GetBuffer(2048); Buffer.BlockCopy(packetData, fragmentHeaderBytes, tempFragmentData, 0, bufferLength - fragmentHeaderBytes); reassemblyData.StoreFragmentData(fragmentChannelID, sequence, ack, ackBits, fragmentID, config.FragmentSize, tempFragmentData, bufferLength - fragmentHeaderBytes); BufferPool.ReturnBuffer(tempFragmentData); if (reassemblyData.NumFragmentsReceived == reassemblyData.NumFragmentsTotal) { // grab internal buffer and pass it to ReceivePacket. Internal buffer will be packet marked as normal packet, so it will go through normal packet path this.ReceivePacket(reassemblyData.PacketDataBuffer.InternalBuffer, reassemblyData.PacketDataBuffer.Length); reassemblyData.PacketDataBuffer.SetSize(0); fragmentReassembly.Remove(sequence); } } }