//Process incoming packet internal void ProcessPacket(NetPacket packet) { //not initialized if (_connectionState == ConnectionState.Outgoing) { _packetPool.Recycle(packet); return; } if (packet.ConnectionNumber != _connectNum && packet.Property != PacketProperty.ShutdownOk) //without connectionNum { NetDebug.Write(NetLogLevel.Trace, "[RR]Old packet"); _packetPool.Recycle(packet); return; } _timeSinceLastPacket = 0; NetDebug.Write("[RR]PacketProperty: {0}", packet.Property); switch (packet.Property) { case PacketProperty.Merged: int pos = NetConstants.HeaderSize; while (pos < packet.Size) { ushort size = BitConverter.ToUInt16(packet.RawData, pos); pos += 2; NetPacket mergedPacket = _packetPool.GetPacket(size); if (!mergedPacket.FromBytes(packet.RawData, pos, size)) { _packetPool.Recycle(packet); break; } pos += size; ProcessPacket(mergedPacket); } break; //If we get ping, send pong case PacketProperty.Ping: if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pongPacket.Sequence) > 0) { NetDebug.Write("[PP]Ping receive, send pong"); FastBitConverter.GetBytes(_pongPacket.RawData, 3, DateTime.UtcNow.Ticks); _pongPacket.Sequence = packet.Sequence; NetManager.SendRaw(_pongPacket, EndPoint); } _packetPool.Recycle(packet); break; //If we get pong, calculate ping time and rtt case PacketProperty.Pong: if (packet.Sequence == _pingPacket.Sequence) { _pingTimer.Stop(); int elapsedMs = (int)_pingTimer.ElapsedMilliseconds; _remoteDelta = BitConverter.ToInt64(packet.RawData, 3) + (elapsedMs * TimeSpan.TicksPerMillisecond) / 2 - DateTime.UtcNow.Ticks; UpdateRoundTripTime(elapsedMs); NetManager.ConnectionLatencyUpdated(this, elapsedMs / 2); NetDebug.Write("[PP]Ping: {0} - {1} - {2}", packet.Sequence, elapsedMs, _remoteDelta); } _packetPool.Recycle(packet); break; case PacketProperty.Ack: case PacketProperty.Channeled: if (packet.ChannelId > _channels.Length) { _packetPool.Recycle(packet); break; } var channel = _channels[packet.ChannelId] ?? (packet.Property == PacketProperty.Ack ? null : CreateChannel(packet.ChannelId)); if (channel != null) { if (!channel.ProcessPacket(packet)) { _packetPool.Recycle(packet); } } break; //Simple packet without acks case PacketProperty.Unreliable: AddIncomingPacket(packet); return; case PacketProperty.MtuCheck: case PacketProperty.MtuOk: ProcessMtuPacket(packet); break; case PacketProperty.ShutdownOk: if (_connectionState == ConnectionState.ShutdownRequested) { _connectionState = ConnectionState.Disconnected; } _packetPool.Recycle(packet); break; default: NetDebug.WriteError("Error! Unexpected packet type: " + packet.Property); break; } }
private void SendInternal( byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod, object userData) { if (_connectionState == ConnectionState.ShutdownRequested || _connectionState == ConnectionState.Disconnected) { return; } if (channelNumber >= _channels.Length) { return; } //Select channel PacketProperty property; BaseChannel channel; if (deliveryMethod == DeliveryMethod.Unreliable) { property = PacketProperty.Unreliable; channel = _unreliableChannel; } else { property = PacketProperty.Channeled; channel = CreateChannel((byte)(channelNumber * 4 + (byte)deliveryMethod)); } //Prepare NetDebug.Write("[RS]Packet: " + property); //Check fragmentation int headerSize = NetPacket.GetHeaderSize(property); //Save mtu for multithread int mtu = _mtu; if (length + headerSize > mtu) { //if cannot be fragmented if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) { throw new TooBigPacketException("Unreliable packet size exceeded maximum of " + (mtu - headerSize) + " bytes"); } int packetFullSize = mtu - headerSize; int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize; int totalPackets = length / packetDataSize + (length % packetDataSize == 0 ? 0 : 1); NetDebug.Write("FragmentSend:\n" + " MTU: {0}\n" + " headerSize: {1}\n" + " packetFullSize: {2}\n" + " packetDataSize: {3}\n" + " totalPackets: {4}", mtu, headerSize, packetFullSize, packetDataSize, totalPackets); if (totalPackets > ushort.MaxValue) { throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue); } lock (_sendLock) { for (ushort partIdx = 0; partIdx < totalPackets; partIdx++) { int sendLength = length > packetDataSize ? packetDataSize : length; NetPacket p = _packetPool.GetPacket(headerSize + sendLength + NetConstants.FragmentHeaderSize); p.Property = property; p.UserData = userData; p.FragmentId = _fragmentId; p.FragmentPart = partIdx; p.FragmentsTotal = (ushort)totalPackets; p.MarkFragmented(); Buffer.BlockCopy(data, partIdx * packetDataSize, p.RawData, NetConstants.FragmentTotalSize, sendLength); channel.AddToQueue(p); length -= sendLength; } _fragmentId++; } return; } //Else just send NetPacket packet = _packetPool.GetPacket(headerSize + length); packet.Property = property; Buffer.BlockCopy(data, start, packet.RawData, headerSize, length); packet.UserData = userData; channel.AddToQueue(packet); }
internal void AddIncomingPacket(NetPacket p) { if (p.IsFragmented) { NetDebug.Write("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal); //Get needed array from dictionary ushort packetFragId = p.FragmentId; IncomingFragments incomingFragments; if (!_holdedFragments.TryGetValue(packetFragId, out incomingFragments)) { incomingFragments = new IncomingFragments { Fragments = new NetPacket[p.FragmentsTotal], ChannelId = p.ChannelId }; _holdedFragments.Add(packetFragId, incomingFragments); } //Cache var fragments = incomingFragments.Fragments; //Error check if (p.FragmentPart >= fragments.Length || fragments[p.FragmentPart] != null || p.ChannelId != incomingFragments.ChannelId) { _packetPool.Recycle(p); NetDebug.WriteError("Invalid fragment packet"); return; } //Fill array fragments[p.FragmentPart] = p; //Increase received fragments count incomingFragments.ReceivedCount++; //Increase total size incomingFragments.TotalSize += p.Size - NetConstants.FragmentTotalSize; //Check for finish if (incomingFragments.ReceivedCount != fragments.Length) { return; } int resultingPacketHeaderSize = NetPacket.GetHeaderSize(p.Property); NetPacket resultingPacket = _packetPool.GetPacket(resultingPacketHeaderSize + incomingFragments.TotalSize); resultingPacket.Property = p.Property; resultingPacket.ChannelId = incomingFragments.ChannelId; int firstFragmentSize = fragments[0].Size - NetConstants.FragmentTotalSize; for (int i = 0; i < incomingFragments.ReceivedCount; i++) { //Create resulting big packet int fragmentSize = fragments[i].Size - NetConstants.FragmentTotalSize; Buffer.BlockCopy( fragments[i].RawData, NetConstants.FragmentTotalSize, resultingPacket.RawData, resultingPacketHeaderSize + firstFragmentSize * i, fragmentSize); //Free memory _packetPool.Recycle(fragments[i]); fragments[i] = null; } //Send to process NetManager.ReceiveFromPeer(resultingPacket, this); //Clear memory _holdedFragments.Remove(packetFragId); } else //Just simple packet { NetManager.ReceiveFromPeer(p, this); } }
/// <summary> /// Gets maximum size of packet that will be not fragmented. /// </summary> /// <param name="options">Type of packet that you want send</param> /// <returns>size in bytes</returns> public int GetMaxSinglePacketSize(DeliveryMethod options) { return(_mtu - NetPacket.GetHeaderSize(options == DeliveryMethod.Unreliable ? PacketProperty.Unreliable : PacketProperty.Channeled)); }