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 flushMessagePacker(bool bufferAck = true) { if (messagePacker.Length > 0) { ushort num = packetController.SendPacket(messagePacker.InternalBuffer, messagePacker.Length, (byte)ChannelID); OutgoingPacketSet outgoingPacketSet = ackBuffer.Insert(num); outgoingPacketSet.MessageIds.Clear(); outgoingPacketSet.MessageIds.AddRange(tempList); messagePacker.SetSize(0); tempList.Clear(); } }
protected void flushMessagePacker(bool bufferAck = true) { if (messagePacker.Length > 0) { ushort outgoingSeq = packetController.SendPacket(messagePacker.InternalBuffer, 0, messagePacker.Length, (byte)ChannelID); var outgoingPacket = ackBuffer.Insert(outgoingSeq); // store message IDs so we can map packet-level acks to message ID acks outgoingPacket.MessageIds.Clear(); outgoingPacket.MessageIds.AddRange(tempList); messagePacker.SetSize(0); tempList.Clear(); } }
public UnreliableMessageChannel() { receiveBuffer = new SequenceBuffer <ReceivedPacketData>(256); config = ReliableConfig.DefaultConfig(); config.TransmitPacketCallback = delegate(byte[] buffer, int size) { TransmitCallback(buffer, size); }; config.ProcessPacketCallback = delegate(ushort seq, byte[] buffer, int size) { if (!receiveBuffer.Exists(seq)) { receiveBuffer.Insert(seq); ReceiveCallback(ChannelID, buffer, size); } }; packetController = new ReliablePacketController(config, DateTime.Now.GetTotalSeconds()); }
public override void SendMessage(byte[] buffer, int bufferPosition, int bufferLength) { int sendBufferSize = 0; for (ushort seq = oldestUnacked; PacketIO.SequenceLessThan(seq, this.sequence); seq++) { if (sendBuffer.Exists(seq)) { sendBufferSize++; } } if (sendBufferSize == sendBuffer.Size) { ByteBuffer tempBuff = ObjPool <ByteBuffer> .Get(); tempBuff.SetSize(bufferLength); tempBuff.BufferCopy(buffer, bufferPosition, 0, bufferLength); messageQueue.Enqueue(tempBuff); return; } ushort sequence = this.sequence++; var packet = sendBuffer.Insert(sequence); packet.time = -1.0; // ensure size for header int varLength = getVariableLengthBytes((ushort)bufferLength); packet.buffer.SetSize(2 + varLength + bufferLength); using (var writer = ByteArrayReaderWriter.Get(packet.buffer.InternalBuffer)) { writer.Write(sequence); writeVariableLengthUShort((ushort)bufferLength, writer); writer.WriteBuffer(buffer, bufferPosition, bufferLength); } // signal that packet is ready to be sent packet.writeLock = false; }
// 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 override void SendMessage(byte[] buffer, int bufferLength) { int num = 0; ushort num2 = oldestUnacked; while (PacketIO.SequenceLessThan(num2, sequence)) { if (sendBuffer.Exists(num2)) { num++; } num2 = (ushort)(num2 + 1); } if (num == sendBuffer.Size) { ByteBuffer byteBuffer = ObjPool <ByteBuffer> .Get(); byteBuffer.SetSize(bufferLength); byteBuffer.BufferCopy(buffer, 0, 0, bufferLength); messageQueue.Enqueue(byteBuffer); } else { ushort val = sequence++; BufferedPacket bufferedPacket = sendBuffer.Insert(val); bufferedPacket.time = -1.0; int variableLengthBytes = getVariableLengthBytes((ushort)bufferLength); bufferedPacket.buffer.SetSize(bufferLength + 2 + variableLengthBytes); using (ByteArrayReaderWriter byteArrayReaderWriter = ByteArrayReaderWriter.Get(bufferedPacket.buffer.InternalBuffer)) { byteArrayReaderWriter.Write(val); writeVariableLengthUShort((ushort)bufferLength, byteArrayReaderWriter); byteArrayReaderWriter.WriteBuffer(buffer, bufferLength); } bufferedPacket.writeLock = false; } }
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 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); } } }