protected void processPacket(ushort seq, byte[] packetData, int packetLen)
 {
     using (ByteArrayReaderWriter byteArrayReaderWriter = ByteArrayReaderWriter.Get(packetData))
     {
         while (byteArrayReaderWriter.ReadPosition < packetLen)
         {
             ushort num  = byteArrayReaderWriter.ReadUInt16();
             ushort num2 = readVariableLengthUShort(byteArrayReaderWriter);
             if (num2 != 0)
             {
                 if (!receiveBuffer.Exists(num))
                 {
                     BufferedPacket bufferedPacket = receiveBuffer.Insert(num);
                     bufferedPacket.buffer.SetSize(num2);
                     byteArrayReaderWriter.ReadBytesIntoBuffer(bufferedPacket.buffer.InternalBuffer, num2);
                 }
                 else
                 {
                     byteArrayReaderWriter.SeekRead(byteArrayReaderWriter.ReadPosition + (int)num2);
                 }
                 while (receiveBuffer.Exists(nextReceive))
                 {
                     BufferedPacket bufferedPacket2 = receiveBuffer.Find(nextReceive);
                     ReceiveCallback(ChannelID, bufferedPacket2.buffer.InternalBuffer, bufferedPacket2.buffer.Length);
                     receiveBuffer.Remove(nextReceive);
                     nextReceive++;
                 }
             }
         }
     }
 }
        protected void ackPacket(ushort seq)
        {
            OutgoingPacketSet outgoingPacketSet = ackBuffer.Find(seq);

            if (outgoingPacketSet == null)
            {
                return;
            }
            for (int i = 0; i < outgoingPacketSet.MessageIds.Count; i++)
            {
                ushort num = outgoingPacketSet.MessageIds[i];
                if (sendBuffer.Exists(num))
                {
                    sendBuffer.Find(num).writeLock = true;
                    sendBuffer.Remove(num);
                }
            }
            bool   flag = true;
            ushort num2 = oldestUnacked;

            while (num2 == sequence || PacketIO.SequenceLessThan(num2, sequence))
            {
                if (sendBuffer.Exists(num2))
                {
                    oldestUnacked = num2;
                    flag          = false;
                    break;
                }
                num2 = (ushort)(num2 + 1);
            }
            if (flag)
            {
                oldestUnacked = sequence;
            }
        }
        protected void processSendBuffer()
        {
            for (ushort seq = oldestUnacked; PacketIO.SequenceLessThan(seq, this.sequence); seq++)
            {
                // never send message ID >= ( oldestUnacked + bufferSize )
                if (seq >= (oldestUnacked + 256))
                {
                    break;
                }

                // for any message that hasn't been sent in the last 0.1 seconds and fits in the available space of our message packer, add it
                var packet = sendBuffer.Find(seq);
                if (packet != null)
                {
                    if (time - packet.time < 0.1)
                    {
                        continue;
                    }

                    bool packetFits = false;

                    if (packet.buffer.Length < config.FragmentThreshold)
                    {
                        packetFits = (messagePacker.Length + packet.buffer.Length) <= (config.FragmentThreshold - Defines.MAX_PACKET_HEADER_BYTES);
                    }
                    else
                    {
                        packetFits = (messagePacker.Length + packet.buffer.Length) <= (config.MaxPacketSize - Defines.FRAGMENT_HEADER_BYTES - Defines.MAX_PACKET_HEADER_BYTES);
                    }

                    // if the packet won't fit, flush the message packer
                    if (!packetFits)
                    {
                        flushMessagePacker();
                    }

                    packet.time = time;

                    int ptr = messagePacker.Length;
                    messagePacker.SetSize(messagePacker.Length + packet.buffer.Length);
                    messagePacker.BufferCopy(packet.buffer, 0, ptr, packet.buffer.Length);

                    tempList.Add(seq);

                    lastMessageSend = time;
                }
            }

            // if it has been 0.1 seconds since the last time we sent a message, send an empty message
            if (time - lastMessageSend >= 0.1)
            {
                sendAckPacket();
                lastMessageSend = time;
            }

            // flush any remaining messages in message packer
            flushMessagePacker();
        }
        protected void processSendBuffer()
        {
            int    num  = 0;
            ushort num2 = oldestUnacked;

            while (PacketIO.SequenceLessThan(num2, sequence))
            {
                num++;
                num2 = (ushort)(num2 + 1);
            }
            ushort num3 = oldestUnacked;

            while (PacketIO.SequenceLessThan(num3, sequence) && num3 < oldestUnacked + 256)
            {
                BufferedPacket bufferedPacket = sendBuffer.Find(num3);
                if (bufferedPacket != null && !bufferedPacket.writeLock && !(time - bufferedPacket.time < 0.1))
                {
                    bool flag = false;
                    if (!((bufferedPacket.buffer.Length >= config.FragmentThreshold) ? (messagePacker.Length + bufferedPacket.buffer.Length <= config.MaxPacketSize - 6 - 10) : (messagePacker.Length + bufferedPacket.buffer.Length <= config.FragmentThreshold - 10)))
                    {
                        flushMessagePacker();
                    }
                    bufferedPacket.time = time;
                    int length = messagePacker.Length;
                    messagePacker.SetSize(messagePacker.Length + bufferedPacket.buffer.Length);
                    messagePacker.BufferCopy(bufferedPacket.buffer, 0, length, bufferedPacket.buffer.Length);
                    tempList.Add(num3);
                    lastMessageSend = time;
                }
                num3 = (ushort)(num3 + 1);
            }
            if (time - lastMessageSend >= 0.1)
            {
                sendAckPacket();
                lastMessageSend = time;
            }
            flushMessagePacker();
        }
        protected void ackPacket(ushort seq)
        {
            // first, map seq to message IDs and ack them
            var outgoingPacket = ackBuffer.Find(seq);

            if (outgoingPacket == null)
            {
                return;
            }

            // process messages
            for (int i = 0; i < outgoingPacket.MessageIds.Count; i++)
            {
                // remove acked message from send buffer
                ushort messageID = outgoingPacket.MessageIds[i];

                if (sendBuffer.Exists(messageID))
                {
                    sendBuffer.Find(messageID).writeLock = true;
                    sendBuffer.Remove(messageID);
                }
            }

            // update oldest unacked message
            bool allAcked = true;

            for (ushort sequence = oldestUnacked; sequence == this.sequence || PacketIO.SequenceLessThan(sequence, this.sequence); sequence++)
            {
                // if it's still in the send buffer, it hasn't been acked
                if (sendBuffer.Exists(sequence))
                {
                    oldestUnacked = sequence;
                    allAcked      = false;
                    break;
                }
            }

            if (allAcked)
            {
                oldestUnacked = this.sequence;
            }
        }
        // process incoming packets and turn them into messages
        protected void processPacket(ushort seq, byte[] packetData, int packetLen)
        {
            using (var reader = ByteArrayReaderWriter.Get(packetData))
            {
                while (reader.ReadPosition < packetLen)
                {
                    // get message bytes and send to receive callback
                    ushort messageID     = reader.ReadUInt16();
                    ushort messageLength = readVariableLengthUShort(reader);

                    if (messageLength == 0)
                    {
                        continue;
                    }

                    if (!receiveBuffer.Exists(messageID))
                    {
                        var receivedMessage = receiveBuffer.Insert(messageID);

                        receivedMessage.buffer.SetSize(messageLength);
                        reader.ReadBytesIntoBuffer(receivedMessage.buffer.InternalBuffer, messageLength);
                    }
                    else
                    {
                        reader.SeekRead(reader.ReadPosition + messageLength);
                    }

                    // keep returning the next message we're expecting as long as it's available
                    while (receiveBuffer.Exists(nextReceive))
                    {
                        var msg = receiveBuffer.Find(nextReceive);

                        ReceiveCallback(msg.buffer.InternalBuffer, msg.buffer.Length);

                        receiveBuffer.Remove(nextReceive);
                        nextReceive++;
                    }
                }
            }
        }
        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 void Update(double newTime)
        {
            this.time = newTime;

            // calculate packet loss
            {
                uint baseSequence = (uint)((sentPackets.sequence - config.SentPacketBufferSize + 1) + 0xFFFF);

                int numDropped = 0;
                int numSamples = config.SentPacketBufferSize / 2;
                for (int i = 0; i < numSamples; i++)
                {
                    ushort sequence       = (ushort)(baseSequence + i);
                    var    sentPacketData = sentPackets.Find(sequence);
                    if (sentPacketData != null && !sentPacketData.acked)
                    {
                        numDropped++;
                    }
                }

                float packetLoss = (float)numDropped / (float)numSamples;
                if (Math.Abs(this.packetLoss - packetLoss) > 0.00001f)
                {
                    this.packetLoss += (packetLoss - this.packetLoss) * config.PacketLossSmoothingFactor;
                }
                else
                {
                    this.packetLoss = packetLoss;
                }
            }

            // calculate sent bandwidth
            {
                uint baseSequence = (uint)((sentPackets.sequence - config.SentPacketBufferSize + 1) + 0xFFFF);

                int    bytesSent  = 0;
                double startTime  = double.MaxValue;
                double finishTime = 0.0;
                int    numSamples = config.SentPacketBufferSize / 2;
                for (int i = 0; i < numSamples; i++)
                {
                    ushort sequence       = (ushort)(baseSequence + i);
                    var    sentPacketData = sentPackets.Find(sequence);
                    if (sentPacketData == null)
                    {
                        continue;
                    }

                    bytesSent += (int)sentPacketData.packetBytes;
                    startTime  = Math.Min(startTime, sentPacketData.time);
                    finishTime = Math.Max(finishTime, sentPacketData.time);
                }

                if (startTime != double.MaxValue && finishTime != 0.0)
                {
                    float sentBandwidth = (float)bytesSent / (float)(finishTime - startTime) * 8f / 1000f;
                    if (Math.Abs(this.sentBandwidthKBPS - sentBandwidth) > 0.00001f)
                    {
                        this.sentBandwidthKBPS += (sentBandwidth - this.sentBandwidthKBPS) * config.BandwidthSmoothingFactor;
                    }
                    else
                    {
                        this.sentBandwidthKBPS = sentBandwidth;
                    }
                }
            }

            // calculate received bandwidth
            lock (receivedPackets)
            {
                uint baseSequence = (uint)((receivedPackets.sequence - config.ReceivedPacketBufferSize + 1) + 0xFFFF);

                int    bytesReceived = 0;
                double startTime     = double.MaxValue;
                double finishTime    = 0.0;
                int    numSamples    = config.ReceivedPacketBufferSize / 2;
                for (int i = 0; i < numSamples; i++)
                {
                    ushort sequence           = (ushort)(baseSequence + i);
                    var    receivedPacketData = receivedPackets.Find(sequence);
                    if (receivedPacketData == null)
                    {
                        continue;
                    }

                    bytesReceived += (int)receivedPacketData.packetBytes;
                    startTime      = Math.Min(startTime, receivedPacketData.time);
                    finishTime     = Math.Max(finishTime, receivedPacketData.time);
                }

                if (startTime != double.MaxValue && finishTime != 0.0)
                {
                    float receivedBandwidth = (float)bytesReceived / (float)(finishTime - startTime) * 8f / 1000f;
                    if (Math.Abs(this.receivedBandwidthKBPS - receivedBandwidth) > 0.00001f)
                    {
                        this.receivedBandwidthKBPS += (receivedBandwidth - this.receivedBandwidthKBPS) * config.BandwidthSmoothingFactor;
                    }
                    else
                    {
                        this.receivedBandwidthKBPS = receivedBandwidth;
                    }
                }
            }

            // calculate acked bandwidth
            {
                uint baseSequence = (uint)((sentPackets.sequence - config.SentPacketBufferSize + 1) + 0xFFFF);

                int    bytesSent  = 0;
                double startTime  = double.MaxValue;
                double finishTime = 0.0;
                int    numSamples = config.SentPacketBufferSize / 2;
                for (int i = 0; i < numSamples; i++)
                {
                    ushort sequence       = (ushort)(baseSequence + i);
                    var    sentPacketData = sentPackets.Find(sequence);
                    if (sentPacketData == null || sentPacketData.acked == false)
                    {
                        continue;
                    }

                    bytesSent += (int)sentPacketData.packetBytes;
                    startTime  = Math.Min(startTime, sentPacketData.time);
                    finishTime = Math.Max(finishTime, sentPacketData.time);
                }

                if (startTime != double.MaxValue && finishTime != 0.0)
                {
                    float ackedBandwidth = (float)bytesSent / (float)(finishTime - startTime) * 8f / 1000f;
                    if (Math.Abs(this.ackedBandwidthKBPS - ackedBandwidth) > 0.00001f)
                    {
                        this.ackedBandwidthKBPS += (ackedBandwidth - this.ackedBandwidthKBPS) * config.BandwidthSmoothingFactor;
                    }
                    else
                    {
                        this.ackedBandwidthKBPS = ackedBandwidth;
                    }
                }
            }
        }
Exemple #9
0
        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;
                }
            }
        }
Exemple #10
0
        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 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);
                }
            }
        }