private BaseChannel CreateChannel(byte idx) { BaseChannel newChannel = _channels[idx]; if (newChannel != null) { return(newChannel); } switch (NetConstants.ChannelIdToDeliveryMethod(idx, _channelsCount)) { case DeliveryMethod.ReliableUnordered: newChannel = new ReliableChannel(this, false, idx); break; case DeliveryMethod.Sequenced: newChannel = new SequencedChannel(this, false, idx); break; case DeliveryMethod.ReliableOrdered: newChannel = new ReliableChannel(this, true, idx); break; case DeliveryMethod.ReliableSequenced: newChannel = new SequencedChannel(this, true, idx); break; } _channels[idx] = newChannel; newChannel.Next = _headChannel; _headChannel = newChannel; return(newChannel); }
/// <summary> /// Send data to peer /// </summary> /// <param name="data">Data</param> /// <param name="start">Start of data</param> /// <param name="length">Length of data</param> /// <param name="channelNumber">Number of channel (from 0 to channelsCount - 1)</param> /// <param name="options">Send options (reliable, unreliable, etc.)</param> /// <exception cref="TooBigPacketException"> /// If size exceeds maximum limit:<para/> /// MTU - headerSize bytes for Unreliable<para/> /// Fragment count exceeded ushort.MaxValue<para/> /// </exception> public void Send(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options) { if (_connectionState == ConnectionState.ShutdownRequested || _connectionState == ConnectionState.Disconnected) { return; } if (channelNumber >= _channelsTotalCount) { return; } //Select channel PacketProperty property; BaseChannel channel; if (options == DeliveryMethod.Unreliable) { property = PacketProperty.Unreliable; channel = _unreliableChannel; } else { property = PacketProperty.Channeled; channel = CreateChannel(NetConstants.ChannelNumberToId(options, channelNumber, _channelsCount)); } //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 (options != DeliveryMethod.ReliableOrdered && options != DeliveryMethod.ReliableUnordered) { throw new TooBigPacketException("Unreliable packet size exceeded maximum of " + (_mtu - headerSize) + " bytes"); } int packetFullSize = mtu - headerSize; int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize; int fullPacketsCount = length / packetDataSize; int lastPacketSize = length % packetDataSize; int totalPackets = fullPacketsCount + (lastPacketSize == 0 ? 0 : 1); NetDebug.Write("FragmentSend:\n" + " MTU: {0}\n" + " headerSize: {1}\n" + " packetFullSize: {2}\n" + " packetDataSize: {3}\n" + " fullPacketsCount: {4}\n" + " lastPacketSize: {5}\n" + " totalPackets: {6}", mtu, headerSize, packetFullSize, packetDataSize, fullPacketsCount, lastPacketSize, totalPackets); if (totalPackets > ushort.MaxValue) { throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue); } int dataOffset = headerSize + NetConstants.FragmentHeaderSize; lock (_sendLock) { for (ushort i = 0; i < fullPacketsCount; i++) { NetPacket p = _packetPool.GetWithProperty(property, packetFullSize); p.FragmentId = _fragmentId; p.FragmentPart = i; p.FragmentsTotal = (ushort)totalPackets; p.MarkFragmented(); Buffer.BlockCopy(data, i * packetDataSize, p.RawData, dataOffset, packetDataSize); channel.AddToQueue(p); } if (lastPacketSize > 0) { NetPacket p = _packetPool.GetWithProperty(property, lastPacketSize + NetConstants.FragmentHeaderSize); p.FragmentId = _fragmentId; p.FragmentPart = (ushort)fullPacketsCount; //last p.FragmentsTotal = (ushort)totalPackets; p.MarkFragmented(); Buffer.BlockCopy(data, fullPacketsCount * packetDataSize, p.RawData, dataOffset, lastPacketSize); channel.AddToQueue(p); } _fragmentId++; } return; } //Else just send NetPacket packet = _packetPool.GetWithData(property, data, start, length); channel.AddToQueue(packet); }