public void AddToQueue(NetPacket packet)
 {
     lock (_outgoingPackets)
     {
         _outgoingPackets.Enqueue(packet);
     }
 }
 public NetPacket GetAndClear()
 {
     var packet = Packet;
     Packet = null;
     TimeStamp = null;
     return packet;
 }
 public void ProcessPacket(NetPacket packet)
 {
     if (NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteSequence) > 0)
     {
         _remoteSequence = packet.Sequence;
         _peer.AddIncomingPacket(packet);
     }
 }
Exemple #4
0
        internal void AddIncomingPacket(NetPacket p)
        {
            if (p.IsFragmented)
            {
                DebugWrite("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]
                    };
                    _holdedFragments.Add(packetFragId, incomingFragments);
                }

                //Cache
                var fragments = incomingFragments.Fragments;

                //Fill array
                fragments[p.FragmentPart] = p;

                //Increase received fragments count
                incomingFragments.ReceivedCount++;

                //Increase total size
                int dataOffset = p.GetHeaderSize() + NetConstants.FragmentHeaderSize;
                incomingFragments.TotalSize += p.RawData.Length - dataOffset;

                //Check for finish
                if (incomingFragments.ReceivedCount != fragments.Length)
                    return;

                DebugWrite("Received all fragments!");
                NetPacket resultingPacket = GetPacketFromPool(p.Property, incomingFragments.TotalSize);
                int resultingPacketOffset = resultingPacket.GetHeaderSize();
                int firstFragmentSize = fragments[0].RawData.Length - dataOffset;
                for (int i = 0; i < incomingFragments.ReceivedCount; i++)
                {
                    //Create resulting big packet
                    int fragmentSize = fragments[i].RawData.Length - dataOffset;
                    Buffer.BlockCopy(
                        fragments[i].RawData,
                        dataOffset,
                        resultingPacket.RawData,
                        resultingPacketOffset + firstFragmentSize * i,
                        fragmentSize);

                    //Free memory
                    Recycle(fragments[i]);
                    fragments[i] = null;
                }

                //Send to process
                _peerListener.ReceiveFromPeer(resultingPacket, _remoteEndPoint);

                //Clear memory
                Recycle(resultingPacket);
                _holdedFragments.Remove(packetFragId);
            }
            else //Just simple packet
            {
                _peerListener.ReceiveFromPeer(p, _remoteEndPoint);
                Recycle(p);
            }
        }
Exemple #5
0
        private void ProcessMtuPacket(NetPacket packet)
        {
            if (packet.RawData.Length == 1 || 
                packet.RawData[1] >= NetConstants.PossibleMtu.Length)
                return;

            //MTU auto increase
            if (packet.Property == PacketProperty.MtuCheck)
            {
                if (packet.RawData.Length != NetConstants.PossibleMtu[packet.RawData[1]])
                {
                    return;
                }
                _mtuCheckAttempts = 0;
                DebugWrite("MTU check. Resend: " + packet.RawData[1]);
                var mtuOkPacket = GetPacketFromPool(PacketProperty.MtuOk, 1);
                mtuOkPacket.RawData[1] = packet.RawData[1];
                SendPacket(mtuOkPacket);
            }
            else if(packet.RawData[1] > _mtuIdx) //MtuOk
            {
                lock (_mtuMutex)
                {
                    _mtuIdx = packet.RawData[1];
                    _mtu = NetConstants.PossibleMtu[_mtuIdx];
                }
                //if maxed - finish.
                if (_mtuIdx == NetConstants.PossibleMtu.Length - 1)
                {
                    _finishMtu = true;
                }
                DebugWrite("MTU ok. Increase to: " + _mtu);
            }
        }
Exemple #6
0
 /// <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(SendOptionsToProperty(options)));
 }
Exemple #7
0
 internal void Recycle(NetPacket packet)
 {
     packet.RawData = null;
     lock (_packetPool)
     {
         _packetPool.Push(packet);
     }
 }
Exemple #8
0
        /// <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="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, DeliveryMethod options)
        {
            if (_connectionState == ConnectionState.ShutdownRequested ||
                _connectionState == ConnectionState.Disconnected)
            {
                return;
            }
            //Prepare
            PacketProperty property = SendOptionsToProperty(options);

            NetUtils.DebugWrite("[RS]Packet: " + property);

            //Select channel
            BaseChannel channel;

            switch (property)
            {
            case PacketProperty.ReliableUnordered:
                channel = _reliableUnorderedChannel;
                break;

            case PacketProperty.Sequenced:
                channel = _sequencedChannel;
                break;

            case PacketProperty.ReliableOrdered:
                channel = _reliableOrderedChannel;
                break;

            case PacketProperty.Unreliable:
                channel = _unreliableChannel;
                break;

            case PacketProperty.ReliableSequenced:
                channel = _reliableSequencedChannel;
                break;

            default:
                throw new InvalidPacketException("Unknown packet property: " + property);
            }

            //Check fragmentation
            int headerSize = NetPacket.GetHeaderSize(property);
            //Save mtu for multithread
            int mtu = _mtu;

            if (length + headerSize > mtu)
            {
                if (options == DeliveryMethod.Sequenced ||
                    options == DeliveryMethod.Unreliable ||
                    options == DeliveryMethod.ReliableSequenced)
                {
                    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);

                NetUtils.DebugWrite("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);
        }
Exemple #9
0
 internal override void ReceiveFromPeer(NetPacket packet, NetEndPoint remoteEndPoint)
 {
     NetPeer fromPeer;
     if (_peers.TryGetValue(remoteEndPoint, out fromPeer))
     {
         var netEvent = CreateEvent(NetEventType.Receive);
         netEvent.Peer = fromPeer;
         netEvent.RemoteEndPoint = fromPeer.EndPoint;
         netEvent.DataReader.SetSource(packet.GetPacketData());
         EnqueueEvent(netEvent);
     }
 }
        //Process incoming packet
        public void ProcessPacket(NetPacket packet)
        {
            if (packet.Sequence >= NetConstants.MaxSequence)
            {
                _peer.DebugWrite("[RR]Bad sequence");
                return;
            }

            int relate = NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteWindowStart);
            int relateSeq = NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteSequence);

            if (relateSeq > _windowSize)
            {
                _peer.DebugWrite("[RR]Bad sequence");
                return;
            }

            //Drop bad packets
            if(relate < 0)
            {
                //Too old packet doesn't ack
                _peer.DebugWrite("[RR]ReliableInOrder too old");
                return;
            }
            if (relate >= _windowSize * 2)
            {
                //Some very new packet
                _peer.DebugWrite("[RR]ReliableInOrder too new");
                return;
            }

            //If very new - move window
            Monitor.Enter(_outgoingAcksAccess);
            if (relate >= _windowSize)
            {
                //New window position
                int newWindowStart = (_remoteWindowStart + relate - _windowSize + 1) % NetConstants.MaxSequence;

                //Clean old data
                while (_remoteWindowStart != newWindowStart)
                {
                    _outgoingAcks[_remoteWindowStart % _windowSize] = false;
                    _remoteWindowStart = (_remoteWindowStart + 1) % NetConstants.MaxSequence;
                }
            }

            //Final stage - process valid packet
            //trigger acks send
            _mustSendAcks = true;

            if (_outgoingAcks[packet.Sequence % _windowSize])
            {
                _peer.DebugWrite("[RR]ReliableInOrder duplicate");
                Monitor.Exit(_outgoingAcksAccess);
                return;
            }

            //save ack
            _outgoingAcks[packet.Sequence % _windowSize] = true;
            Monitor.Exit(_outgoingAcksAccess);

            //detailed check
            if (packet.Sequence == _remoteSequence)
            {
                _peer.DebugWrite("[RR]ReliableInOrder packet succes");
                _peer.AddIncomingPacket(packet);
                _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;

                if (_ordered)
                {
                    NetPacket p;
                    while ( (p = _receivedPackets[_remoteSequence % _windowSize]) != null)
                    {
                        //process holded packet
                        _receivedPackets[_remoteSequence % _windowSize] = null;
                        _peer.AddIncomingPacket(p);
                        _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
                    }
                }
                else
                {
                    while (_earlyReceived[_remoteSequence % _windowSize])
                    {
                        //process early packet
                        _earlyReceived[_remoteSequence % _windowSize] = false;
                        _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
                    }
                }

                return;
            }

            //holded packet
            if (_ordered)
            {
                _receivedPackets[packet.Sequence % _windowSize] = packet;
            }
            else
            {
                _earlyReceived[packet.Sequence % _windowSize] = true;
                _peer.AddIncomingPacket(packet);
            }
        }
Exemple #11
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            _timeSinceLastPacket = 0;
            if (packet.ConnectionNumber != _connectNum &&
                packet.Property != PacketProperty.ShutdownOk) //withou connectionNum
            {
                NetUtils.DebugWrite(ConsoleColor.Red, "[RR]Old packet");
                _packetPool.Recycle(packet);
                return;
            }

            NetUtils.DebugWrite("[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, false);
                    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, _remotePingSequence) < 0)
                {
                    _packetPool.Recycle(packet);
                    break;
                }
                NetUtils.DebugWrite("[PP]Ping receive, send pong");
                _remotePingSequence = packet.Sequence;
                _packetPool.Recycle(packet);

                //send
                _pongPacket.Sequence = _remotePingSequence;
                _netManager.SendRaw(_pongPacket, _remoteEndPoint);
                break;

            //If we get pong, calculate ping time and rtt
            case PacketProperty.Pong:
                if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pingSequence) < 0)
                {
                    _packetPool.Recycle(packet);
                    break;
                }
                _pingSequence = packet.Sequence;
                int rtt = (int)(DateTime.UtcNow - _pingTimeStart).TotalMilliseconds;
                UpdateRoundTripTime(rtt);
                NetUtils.DebugWrite("[PP]Ping: {0}", rtt);
                _packetPool.Recycle(packet);
                break;

            //Process ack
            case PacketProperty.AckReliable:
                _reliableUnorderedChannel.ProcessAck(packet);
                _packetPool.Recycle(packet);
                break;

            case PacketProperty.AckReliableOrdered:
                _reliableOrderedChannel.ProcessAck(packet);
                _packetPool.Recycle(packet);
                break;

            //Process in order packets
            case PacketProperty.Sequenced:
                _sequencedChannel.ProcessPacket(packet);
                break;

            case PacketProperty.ReliableUnordered:
                _reliableUnorderedChannel.ProcessPacket(packet);
                break;

            case PacketProperty.ReliableOrdered:
                _reliableOrderedChannel.ProcessPacket(packet);
                break;

            case PacketProperty.ReliableSequenced:
                _reliableSequencedChannel.ProcessPacket(packet);
                break;

            case PacketProperty.AckReliableSequenced:
                _reliableSequencedChannel.ProcessAck(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:
                NetUtils.DebugWriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
        internal void Update(int deltaTime)
        {
            Interlocked.Add(ref _timeSinceLastPacket, deltaTime);
            switch (_connectionState)
            {
            case ConnectionState.Connected:
                if (_timeSinceLastPacket > NetManager.DisconnectTimeout)
                {
                    NetDebug.Write(
                        "[UPDATE] Disconnect by timeout: {0} > {1}",
                        _timeSinceLastPacket,
                        NetManager.DisconnectTimeout);
                    NetManager.DisconnectPeerForce(this, DisconnectReason.Timeout, 0, null);
                    return;
                }
                break;

            case ConnectionState.ShutdownRequested:
                if (_timeSinceLastPacket > NetManager.DisconnectTimeout)
                {
                    _connectionState = ConnectionState.Disconnected;
                }
                else
                {
                    _shutdownTimer += deltaTime;
                    if (_shutdownTimer >= ShutdownDelay)
                    {
                        _shutdownTimer = 0;
                        NetManager.SendRaw(_shutdownPacket, EndPoint);
                    }
                }
                return;

            case ConnectionState.Outgoing:
                _connectTimer += deltaTime;
                if (_connectTimer > NetManager.ReconnectDelay)
                {
                    _connectTimer = 0;
                    _connectAttempts++;
                    if (_connectAttempts > NetManager.MaxConnectAttempts)
                    {
                        NetManager.DisconnectPeerForce(this, DisconnectReason.ConnectionFailed, 0, null);
                        return;
                    }

                    //else send connect again
                    NetManager.SendRaw(_connectRequestPacket, EndPoint);
                }
                return;

            case ConnectionState.Disconnected:
                return;
            }

            //Send ping
            _pingSendTimer += deltaTime;
            if (_pingSendTimer >= NetManager.PingInterval)
            {
                NetDebug.Write("[PP] Send ping...");
                //reset timer
                _pingSendTimer = 0;
                //send ping
                _pingPacket.Sequence++;
                //ping timeout
                if (_pingTimer.IsRunning)
                {
                    UpdateRoundTripTime((int)_pingTimer.ElapsedMilliseconds);
                }
                _pingTimer.Reset();
                _pingTimer.Start();
                NetManager.SendRaw(_pingPacket, EndPoint);
            }

            //RTT - round trip time
            _rttResetTimer += deltaTime;
            if (_rttResetTimer >= NetManager.PingInterval * 3)
            {
                _rttResetTimer = 0;
                _rtt           = _avgRtt;
                _rttCount      = 1;
            }

            UpdateMtuLogic(deltaTime);

            //Pending send
            BaseChannel currentChannel = _headChannel;

            while (currentChannel != null)
            {
                currentChannel.SendNextPackets();
                currentChannel = currentChannel.Next;
            }

            lock (_unreliableChannel)
            {
                while (_unreliableChannel.Count > 0)
                {
                    NetPacket packet = _unreliableChannel.Dequeue();
                    SendUserData(packet);
                    NetManager.NetPacketPool.Recycle(packet);
                }
            }

            SendMerged();
        }
 /// <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));
 }
        //Process incoming packet
        public override bool ProcessPacket(NetPacket packet)
        {
            if (packet.Property == PacketProperty.Ack)
            {
                ProcessAck(packet);
                return(false);
            }
            int seq = packet.Sequence;

            if (seq >= NetConstants.MaxSequence)
            {
                NetDebug.Write("[RR]Bad sequence");
                return(false);
            }

            int relate    = NetUtils.RelativeSequenceNumber(seq, _remoteWindowStart);
            int relateSeq = NetUtils.RelativeSequenceNumber(seq, _remoteSequence);

            if (relateSeq > _windowSize)
            {
                NetDebug.Write("[RR]Bad sequence");
                return(false);
            }

            //Drop bad packets
            if (relate < 0)
            {
                //Too old packet doesn't ack
                NetDebug.Write("[RR]ReliableInOrder too old");
                return(false);
            }
            if (relate >= _windowSize * 2)
            {
                //Some very new packet
                NetDebug.Write("[RR]ReliableInOrder too new");
                return(false);
            }

            //If very new - move window
            int ackIdx;
            int ackByte;
            int ackBit;

            lock (_outgoingAcks)
            {
                if (relate >= _windowSize)
                {
                    //New window position
                    int newWindowStart = (_remoteWindowStart + relate - _windowSize + 1) % NetConstants.MaxSequence;
                    _outgoingAcks.Sequence = (ushort)newWindowStart;

                    //Clean old data
                    while (_remoteWindowStart != newWindowStart)
                    {
                        ackIdx  = _remoteWindowStart % _windowSize;
                        ackByte = NetConstants.ChanneledHeaderSize + ackIdx / BitsInByte;
                        ackBit  = ackIdx % BitsInByte;
                        _outgoingAcks.RawData[ackByte] &= (byte)~(1 << ackBit);
                        _remoteWindowStart              = (_remoteWindowStart + 1) % NetConstants.MaxSequence;
                    }
                }

                //Final stage - process valid packet
                //trigger acks send
                _mustSendAcks = true;
                ackIdx        = seq % _windowSize;
                ackByte       = NetConstants.ChanneledHeaderSize + ackIdx / BitsInByte;
                ackBit        = ackIdx % BitsInByte;
                if ((_outgoingAcks.RawData[ackByte] & (1 << ackBit)) != 0)
                {
                    NetDebug.Write("[RR]ReliableInOrder duplicate");
                    return(false);
                }

                //save ack
                _outgoingAcks.RawData[ackByte] |= (byte)(1 << ackBit);
            }

            //detailed check
            if (seq == _remoteSequence)
            {
                NetDebug.Write("[RR]ReliableInOrder packet succes");
                Peer.AddIncomingPacket(packet);
                _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;

                if (_ordered)
                {
                    NetPacket p;
                    while ((p = _receivedPackets[_remoteSequence % _windowSize]) != null)
                    {
                        //process holded packet
                        _receivedPackets[_remoteSequence % _windowSize] = null;
                        Peer.AddIncomingPacket(p);
                        _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
                    }
                }
                else
                {
                    while (_earlyReceived[_remoteSequence % _windowSize])
                    {
                        //process early packet
                        _earlyReceived[_remoteSequence % _windowSize] = false;
                        _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
                    }
                }
                return(true);
            }

            //holded packet
            if (_ordered)
            {
                _receivedPackets[ackIdx] = packet;
            }
            else
            {
                _earlyReceived[ackIdx] = true;
                Peer.AddIncomingPacket(packet);
            }
            return(true);
        }
 public void Init(NetPacket packet)
 {
     _packet = packet;
     _isSent = false;
 }
        //ProcessAck in packet
        private void ProcessAck(NetPacket packet)
        {
            if (packet.Size != _outgoingAcks.Size)
            {
                NetDebug.Write("[PA]Invalid acks packet size");
                return;
            }

            ushort ackWindowStart = packet.Sequence;
            int    windowRel      = NetUtils.RelativeSequenceNumber(_localWindowStart, ackWindowStart);

            if (ackWindowStart >= NetConstants.MaxSequence || windowRel < 0)
            {
                NetDebug.Write("[PA]Bad window start");
                return;
            }

            //check relevance
            if (windowRel >= _windowSize)
            {
                NetDebug.Write("[PA]Old acks");
                return;
            }

            byte[] acksData = packet.RawData;
            lock (_pendingPackets)
            {
                for (int pendingSeq = _localWindowStart;
                     pendingSeq != _localSeqence;
                     pendingSeq = (pendingSeq + 1) % NetConstants.MaxSequence)
                {
                    int rel = NetUtils.RelativeSequenceNumber(pendingSeq, ackWindowStart);
                    if (rel >= _windowSize)
                    {
                        NetDebug.Write("[PA]REL: " + rel);
                        break;
                    }

                    int pendingIdx  = pendingSeq % _windowSize;
                    int currentByte = NetConstants.ChanneledHeaderSize + pendingIdx / BitsInByte;
                    int currentBit  = pendingIdx % BitsInByte;
                    if ((acksData[currentByte] & (1 << currentBit)) == 0)
                    {
#if STATS_ENABLED || DEBUG
                        Peer.Statistics.PacketLoss++;
#endif
                        //Skip false ack
                        NetDebug.Write("[PA]False ack: {0}", pendingSeq);
                        continue;
                    }

                    if (pendingSeq == _localWindowStart)
                    {
                        //Move window
                        _localWindowStart = (_localWindowStart + 1) % NetConstants.MaxSequence;
                    }

                    //clear packet
                    if (_pendingPackets[pendingIdx].Clear(Peer))
                    {
                        NetDebug.Write("[PA]Removing reliableInOrder ack: {0} - true", pendingSeq);
                    }
                }
            }
        }
Exemple #17
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            _lastPacketReceivedStart = DateTime.UtcNow;

            DebugWrite("[RR]PacketProperty: {0}", packet.Property);
            switch (packet.Property)
            {
                case PacketProperty.Merged:
                    int pos = NetConstants.HeaderSize;
                    while (pos < packet.RawData.Length)
                    {
                        ushort size = BitConverter.ToUInt16(packet.RawData, pos);
                        pos += 2;
                        NetPacket mergedPacket = GetPacketFromPool(init: false);
                        if (!mergedPacket.FromBytes(packet.RawData, pos, size))
                        {
                            Recycle(packet);
                            break;
                        }
                        pos += size;
                        ProcessPacket(mergedPacket);
                    }
                    break;
                //If we get ping, send pong
                case PacketProperty.Ping:
                    if (NetUtils.RelativeSequenceNumber(packet.Sequence, _remotePingSequence) < 0)
                    {
                        Recycle(packet);
                        break;
                    }
                    DebugWrite("[PP]Ping receive, send pong");
                    _remotePingSequence = packet.Sequence;
                    Recycle(packet);

                    //send
                    CreateAndSend(PacketProperty.Pong, _remotePingSequence);
                    break;

                //If we get pong, calculate ping time and rtt
                case PacketProperty.Pong:
                    if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pingSequence) < 0)
                    {
                        Recycle(packet);
                        break;
                    }
                    _pingSequence = packet.Sequence;
                    int rtt = (int)(DateTime.UtcNow - _pingTimeStart).TotalMilliseconds;
                    UpdateRoundTripTime(rtt);
                    DebugWrite("[PP]Ping: {0}", rtt);
                    Recycle(packet);
                    break;

                //Process ack
                case PacketProperty.AckReliable:
                    _reliableUnorderedChannel.ProcessAck(packet);
                    Recycle(packet);
                    break;

                case PacketProperty.AckReliableOrdered:
                    _reliableOrderedChannel.ProcessAck(packet);
                    Recycle(packet);
                    break;

                //Process in order packets
                case PacketProperty.Sequenced:
                    _sequencedChannel.ProcessPacket(packet);
                    break;

                case PacketProperty.Reliable:
                    _reliableUnorderedChannel.ProcessPacket(packet);
                    break;

                case PacketProperty.ReliableOrdered:
                    _reliableOrderedChannel.ProcessPacket(packet);
                    break;

                //Simple packet without acks
                case PacketProperty.Unreliable:
                    AddIncomingPacket(packet);
                    return;

                case PacketProperty.MtuCheck:
                case PacketProperty.MtuOk:
                    ProcessMtuPacket(packet);
                    break;

                default:
                    DebugWriteForce("Error! Unexpected packet type: " + packet.Property);
                    break;
            }
        }
Exemple #18
0
 internal abstract void ReceiveFromPeer(NetPacket packet, NetEndPoint endPoint);
        private void SendInternal(
            byte[] data,
            int start,
            int length,
            byte channelNumber,
            DeliveryMethod deliveryMethod,
            object userData)
        {
            if (_connectionState != ConnectionState.Connected || channelNumber >= _channels.Length)
            {
                return;
            }

            //Select channel
            PacketProperty property;
            BaseChannel    channel = null;

            if (deliveryMethod == DeliveryMethod.Unreliable)
            {
                property = PacketProperty.Unreliable;
            }
            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);
                }

                ushort currentFragmentId = (ushort)Interlocked.Increment(ref _fragmentId);

                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     = currentFragmentId;
                    p.FragmentPart   = partIdx;
                    p.FragmentsTotal = (ushort)totalPackets;
                    p.MarkFragmented();

                    Buffer.BlockCopy(data, partIdx * packetDataSize, p.RawData, NetConstants.FragmentedHeaderTotalSize, sendLength);
                    channel.AddToQueue(p);

                    length -= sendLength;
                }
                return;
            }

            //Else just send
            NetPacket packet = _packetPool.GetPacket(headerSize + length);

            packet.Property = property;
            Buffer.BlockCopy(data, start, packet.RawData, headerSize, length);
            packet.UserData = userData;

            if (channel == null) //unreliable
            {
                lock (_unreliableChannel)
                    _unreliableChannel.Enqueue(packet);
            }
            else
            {
                channel.AddToQueue(packet);
            }
        }
Exemple #20
0
        internal void AddIncomingPacket(NetPacket p)
        {
            if (p.IsFragmented)
            {
                NetUtils.DebugWrite("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]
                    };
                    _holdedFragments.Add(packetFragId, incomingFragments);
                }

                //Cache
                var fragments = incomingFragments.Fragments;

                //Error check
                if (p.FragmentPart >= fragments.Length || fragments[p.FragmentPart] != null)
                {
                    _packetPool.Recycle(p);
                    NetUtils.DebugWriteError("Invalid fragment packet");
                    return;
                }
                //Fill array
                fragments[p.FragmentPart] = p;

                //Increase received fragments count
                incomingFragments.ReceivedCount++;

                //Increase total size
                int dataOffset = p.GetHeaderSize() + NetConstants.FragmentHeaderSize;
                incomingFragments.TotalSize += p.Size - dataOffset;

                //Check for finish
                if (incomingFragments.ReceivedCount != fragments.Length)
                {
                    return;
                }

                NetUtils.DebugWrite("Received all fragments!");
                NetPacket resultingPacket = _packetPool.GetWithProperty(p.Property, incomingFragments.TotalSize);

                int resultingPacketOffset = resultingPacket.GetHeaderSize();
                int firstFragmentSize     = fragments[0].Size - dataOffset;
                for (int i = 0; i < incomingFragments.ReceivedCount; i++)
                {
                    //Create resulting big packet
                    int fragmentSize = fragments[i].Size - dataOffset;
                    Buffer.BlockCopy(
                        fragments[i].RawData,
                        dataOffset,
                        resultingPacket.RawData,
                        resultingPacketOffset + firstFragmentSize * i,
                        fragmentSize);

                    //Free memory
                    _packetPool.Recycle(fragments[i]);
                    fragments[i] = null;
                }

                //Send to process
                _netManager.ReceiveFromPeer(resultingPacket, _remoteEndPoint);

                //Clear memory
                _holdedFragments.Remove(packetFragId);
            }
            else //Just simple packet
            {
                _netManager.ReceiveFromPeer(p, _remoteEndPoint);
            }
        }
        //ProcessAck in packet
        public void ProcessAck(NetPacket packet)
        {
            int validPacketSize = (_windowSize - 1) / BitsInByte + 1 + NetConstants.SequencedHeaderSize;
            if (packet.RawData.Length != validPacketSize)
            {
                _peer.DebugWriteForce("[PA]Invalid acks packet size");
                return;
            }

            ushort ackWindowStart = packet.Sequence;
            if (ackWindowStart > NetConstants.MaxSequence)
            {
                _peer.DebugWrite("[PA]Bad window start");
                return;
            }

            //check relevance
            if (NetUtils.RelativeSequenceNumber(ackWindowStart, _localWindowStart) <= -_windowSize)
            {
                _peer.DebugWrite("[PA]Old acks");
                return;
            }

            byte[] acksData = packet.RawData;
            _peer.DebugWrite("[PA]AcksStart: {0}", ackWindowStart);
            int startByte = NetConstants.SequencedHeaderSize;

            Monitor.Enter(_pendingPacketsAccess);
            for (int i = 0; i < _windowSize; i++)
            {
                int ackSequence = (ackWindowStart + i) % NetConstants.MaxSequence;
                if (NetUtils.RelativeSequenceNumber(ackSequence, _localWindowStart) < 0)
                {
                    //Skip old ack
                    continue;
                }

                int currentByte = startByte + i / BitsInByte;
                int currentBit = i % BitsInByte;

                if ((acksData[currentByte] & (1 << currentBit)) == 0)
                {
                    //Skip false ack
                    continue;
                }

                if (ackSequence == _localWindowStart)
                {
                    //Move window
                    _localWindowStart = (_localWindowStart + 1) % NetConstants.MaxSequence;
                }

                int storeIdx = ackSequence % _windowSize;
                if (_pendingPackets[storeIdx].NotEmpty)
                {
                    NetPacket removed = _pendingPackets[storeIdx].GetAndClear();
                    _peer.Recycle(removed);

                    _peer.DebugWrite("[PA]Removing reliableInOrder ack: {0} - true", ackSequence);
                }
                else
                {
                    _peer.DebugWrite("[PA]Removing reliableInOrder ack: {0} - false", ackSequence);
                }
            }
            Monitor.Exit(_pendingPacketsAccess);
        }
        internal void AddReliablePacket(DeliveryMethod method, 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.FragmentedHeaderTotalSize;

                //Check for finish
                if (incomingFragments.ReceivedCount != fragments.Length)
                {
                    return;
                }

                //just simple packet
                NetPacket resultingPacket = _packetPool.GetPacket(incomingFragments.TotalSize);

                int firstFragmentSize = fragments[0].Size - NetConstants.FragmentedHeaderTotalSize;
                for (int i = 0; i < incomingFragments.ReceivedCount; i++)
                {
                    var fragment = fragments[i];
                    //Create resulting big packet
                    Buffer.BlockCopy(
                        fragment.RawData,
                        NetConstants.FragmentedHeaderTotalSize,
                        resultingPacket.RawData,
                        firstFragmentSize * i,
                        fragment.Size - NetConstants.FragmentedHeaderTotalSize);

                    //Free memory
                    _packetPool.Recycle(fragment);
                }
                Array.Clear(fragments, 0, incomingFragments.ReceivedCount);

                //Send to process
                NetManager.CreateReceiveEvent(resultingPacket, method, 0, this);

                //Clear memory
                _holdedFragments.Remove(packetFragId);
            }
            else //Just simple packet
            {
                NetManager.CreateReceiveEvent(p, method, NetConstants.ChanneledHeaderSize, this);
            }
        }
Exemple #23
0
 internal override void ReceiveFromPeer(NetPacket packet, NetEndPoint remoteEndPoint)
 {
     NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Received message");
     var netEvent = CreateEvent(NetEventType.Receive);
     netEvent.DataReader.SetSource(packet.GetPacketData());
     netEvent.Peer = _peer;
     netEvent.RemoteEndPoint = remoteEndPoint;
     EnqueueEvent(netEvent);
 }
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            //not initialized
            if (_connectionState == ConnectionState.Outgoing || _connectionState == ConnectionState.Disconnected)
            {
                _packetPool.Recycle(packet);
                return;
            }
            if (packet.Property == PacketProperty.ShutdownOk)
            {
                if (_connectionState == ConnectionState.ShutdownRequested)
                {
                    _connectionState = ConnectionState.Disconnected;
                }
                _packetPool.Recycle(packet);
                return;
            }
            if (packet.ConnectionNumber != _connectNum)
            {
                NetDebug.Write(NetLogLevel.Trace, "[RR]Old packet");
                _packetPool.Recycle(packet);
                return;
            }
            Interlocked.Exchange(ref _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:
                NetManager.CreateReceiveEvent(packet, DeliveryMethod.Unreliable, NetConstants.HeaderSize, this);
                return;

            case PacketProperty.MtuCheck:
            case PacketProperty.MtuOk:
                ProcessMtuPacket(packet);
                break;

            default:
                NetDebug.WriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
Exemple #25
0
 //from user thread, our thread, or recv?
 private void SendPacket(NetPacket packet)
 {
     switch (packet.Property)
     {
         case PacketProperty.Reliable:
             DebugWrite("[RS]Packet reliable");
             _reliableUnorderedChannel.AddToQueue(packet);
             break;
         case PacketProperty.Sequenced:
             DebugWrite("[RS]Packet sequenced");
             _sequencedChannel.AddToQueue(packet);
             break;
         case PacketProperty.ReliableOrdered:
             DebugWrite("[RS]Packet reliable ordered");
             _reliableOrderedChannel.AddToQueue(packet);
             break;
         case PacketProperty.Unreliable:
             DebugWrite("[RS]Packet simple");
             _simpleChannel.AddToQueue(packet);
             break;
         case PacketProperty.MtuCheck:
             //Must check result for MTU fix
             if (!_peerListener.SendRaw(packet.RawData, 0, packet.RawData.Length, _remoteEndPoint))
             {
                 _finishMtu = true;
             }
             Recycle(packet);
             break;
         case PacketProperty.AckReliable:
         case PacketProperty.AckReliableOrdered:
         case PacketProperty.Ping:
         case PacketProperty.Pong:
         case PacketProperty.Disconnect:
         case PacketProperty.MtuOk:
             SendRawData(packet.RawData);
             Recycle(packet);
             break;
         default:
             throw new Exception("Unknown packet property: " + packet.Property);
     }
 }
Exemple #26
0
 internal NetPacket GetPacketFromPool(PacketProperty property = PacketProperty.Unreliable, int size=0, bool init=true)
 {
     NetPacket packet = null;
     lock (_packetPool)
     {
         if (_packetPool.Count > 0)
         {
             packet = _packetPool.Pop();
         }
     }
     if(packet == null)
     {
         packet = new NetPacket();
     }
     if(init)
         packet.Init(property, size);
     return packet;
 }
Exemple #27
0
        protected override void ReceiveFromSocket(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint)
        {
            NetPacket packet;
            NetPeer netPeer;

            //Check peers
            if (_peers.TryGetValue(remoteEndPoint, out netPeer))
            {
                packet = netPeer.GetPacketFromPool(init: false);

                //Bad packet check
                if (!packet.FromBytes(reusableBuffer, 0, count))
                {
                    netPeer.Recycle(packet);
                    return;
                }
                
                //Send
                if (packet.Property == PacketProperty.Disconnect)
                {
                    if (BitConverter.ToUInt64(packet.RawData, 1) != _peerConnectionIds[remoteEndPoint])
                    {
                        //Old or incorrect disconnect
                        netPeer.Recycle(packet);
                        return;
                    }
                    RemovePeer(netPeer);
                    var netEvent = CreateEvent(NetEventType.Disconnect);
                    netEvent.Peer = netPeer;
                    netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose;
                    EnqueueEvent(netEvent);
                }
                else if (packet.Property == PacketProperty.ConnectRequest) //response with connect
                {
                    ulong lastId = _peerConnectionIds[remoteEndPoint];
                    ulong newId = BitConverter.ToUInt64(packet.RawData, 1);
                    if (newId > lastId)
                    {
                        _peerConnectionIds[remoteEndPoint] = newId;
                    }
                    
                    NetUtils.DebugWrite(ConsoleColor.Cyan, "ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", lastId, newId, remoteEndPoint);
                    SendConnectAccept(netPeer, _peerConnectionIds[remoteEndPoint]);
                    netPeer.Recycle(packet);
                }
                else //throw out garbage packets
                {
                    netPeer.ProcessPacket(packet);
                }
                return;
            }

            //Else add new peer
            packet = new NetPacket();
            if (!packet.FromBytes(reusableBuffer, 0, count))
            {
                //Bad packet
                return;
            }

            if (_peers.Count < _maxClients && packet.Property == PacketProperty.ConnectRequest)
            {
                string peerKey = Encoding.UTF8.GetString(packet.RawData, 9, packet.RawData.Length - 9);
                if (peerKey != _connectKey)
                {
                    NetUtils.DebugWrite(ConsoleColor.Cyan, "[NS] Peer connect reject. Invalid key: " + peerKey);
                    return;
                }

                //Getting new id for peer
                netPeer = CreatePeer(remoteEndPoint);

                //response with id
                ulong connectionId = BitConverter.ToUInt64(packet.RawData, 1);
                NetUtils.DebugWrite(ConsoleColor.Cyan, "[NS] Received peer connect request Id: {0}, EP: {1}", connectionId, remoteEndPoint);


                SendConnectAccept(netPeer, connectionId);

                //clean incoming packet
                netPeer.Recycle(packet);

                lock (_peers)
                {
                    _peers.Add(remoteEndPoint, netPeer);
                    _peerConnectionIds.Add(remoteEndPoint, connectionId);
                }

                var netEvent = CreateEvent(NetEventType.Connect);
                netEvent.Peer = netPeer;
                EnqueueEvent(netEvent);
            }
        }
Exemple #28
0
 //For channels
 internal void Recycle(NetPacket packet)
 {
     _packetPool.Recycle(packet);
 }