Ejemplo n.º 1
0
        public bool ProcessPacket(NetPacket packet)
        {
            if (packet.IsFragmented)
            {
                return(false);
            }

            if (packet.Property == PacketProperty.Ack)
            {
                if (_reliable && _lastPacket != null && packet.Sequence == _lastPacket.Sequence)
                {
                    _lastPacket = null;
                }
                return(false);
            }

            int  relative        = NetUtil.RelativeSequenceNumber(packet.Sequence, _remoteSequence);
            bool packetProcessed = false;

            if (packet.Sequence < NetPacket.MaxSequence && relative > 0)
            {
                if (_reliable)
                {
                    Interlocked.Add(ref _statistic.UdpPacketLossCount, (relative - 1));
                }

                _remoteSequence = packet.Sequence;

                _udpChannel.PacketReceived?.Invoke(_udpChannel, packet);

                packetProcessed = true;
            }

            _mustSendAck = true;
            return(packetProcessed);
        }
Ejemplo n.º 2
0
        internal void OnReceivedRawUdpData(byte[] data, int size, NetPacket cachedPacket, SocketError error, IPEndPoint endPoint)
        {
            //Console.WriteLine($"buffer size : {size}   packet size : {BitConverter.ToUInt16(data, 0)}");

            if (size < NetPacket.HeaderSize)
                return;

            try
            {
                PacketProperty property = cachedPacket.Property;
                DeliveryMethod deliveryMethod = cachedPacket.DeliveryMethod;

                switch (property)
                {

                    case PacketProperty.MtuCheck:
                        {
                            NetPacket packet = NetPool.PacketPool.Alloc(NetPacket.GetHeaderSize(PacketProperty.MtuOk));

                            try
                            {
                                byte getMtuId = data[3];

                                packet.Property = PacketProperty.MtuOk;
                                packet.DeliveryMethod = DeliveryMethod.Unreliable;
                                packet.RawData[3] = getMtuId;

                                SendTo(packet.RawData, 0, packet.Size, SendMode.Immediately);
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(ex, "Exception happened in MtuCheck");
                            }
                            finally
                            {
                                NetPool.PacketPool.Free(packet);
                            }
                        }
                        break;
                    case PacketProperty.MtuOk:
                        {
                            try
                            {
                                byte getMtuId = data[3];

                                if (getMtuId >= _mtuId)
                                {
                                    _mtuId = getMtuId;
                                    _mtu = NetPacket.PossibleMtu[getMtuId];

                                    if (_mtuId >= NetPacket.PossibleMtu.Length)
                                        _finishMtu = true;

                                    //Console.WriteLine($"SetMtu : {_mtu}");
                                }
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(ex, "Exception happened in MtuOk");
                            }
                        }
                        break;
                    case PacketProperty.Ping:
                        {
                            ushort sequence = BitConverter.ToUInt16(data, 3);

                            if (NetUtil.RelativeSequenceNumber(sequence, _pongPacket.Sequence) > 0)
                            {
                                FastBitConverter.GetBytes(_pongPacket.RawData, 5, DateTime.UtcNow.Ticks);
                                _pongPacket.Sequence = sequence;
                                SendTo(_pongPacket.RawData, 0, _pongPacket.Size, SendMode.Immediately);
                            }
                        }
                        break;
                    case PacketProperty.Pong:
                        {
                            ushort sequence = BitConverter.ToUInt16(data, 3);

                            if (sequence == _pingPacket.Sequence)
                            {
                                _pingTimer.Stop();
                                int elapsedMs = (int)_pingTimer.ElapsedMilliseconds;
                                _remoteTickDelta = BitConverter.ToInt64(data, 5) + (elapsedMs * TimeSpan.TicksPerMillisecond) / 2 - DateTime.UtcNow.Ticks;
                                UpdateRoundTripTime(elapsedMs);

                                //Console.WriteLine($"Pong sequence : {sequence}  {elapsedMs} ms  {_remoteTickDelta} microseconds");
                            }
                        }
                        break;
                    default:
                        {
                            ReadPacket(data, size, _channelOption.PacketFilter);
                        }
                        break;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Exception happened in OnReceivedRawUdpData");
                Close();
            }
        }
Ejemplo n.º 3
0
        public bool ProcessPacket(NetPacket poolingPacket)
        {
            if (poolingPacket.Property == PacketProperty.Ack)
            {
                try
                {
                    ProcessAck(poolingPacket);
                }
                finally
                {
                    NetPool.PacketPool.Free(poolingPacket);
                }

                return(false);
            }

            int seq = poolingPacket.Sequence;

            if (seq >= NetPacket.MaxSequence)
            {
#if RELIABLE_LOG
                Console.WriteLine($"rudp bad sequence {seq}");
#endif
                return(false);
            }

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

            if (relateSeq > WindowSize)
            {
#if RELIABLE_LOG
                Console.WriteLine($"rudp bad relative sequence {relateSeq}");
#endif
                return(false);
            }

            if (relate < 0)
            {
                // 너무 오래된 패킷임
#if RELIABLE_LOG
                Console.WriteLine($"rudp ReliableInOrder too old");
#endif
                return(false);
            }
            if (relate >= WindowSize * 2)
            {
                // 너무 새로운 패킷임
#if RELIABLE_LOG
                Console.WriteLine($"rudp ReliableInOrder too new");
#endif
                return(false);
            }

            int ackIdx;
            int ackByte;
            int ackBit;

            // 응답패킷 데이터를 태우자
            lock (_ackPacket)
            {
                if (relate >= WindowSize)
                {
                    int newWindowStart = (_remoteWindowStart + relate - WindowSize + 1) % NetPacket.MaxSequence;
                    _ackPacket.Sequence = (ushort)newWindowStart;

                    // 예전 데이터를 정리
                    while (_remoteWindowStart != newWindowStart)
                    {
                        ackIdx  = _remoteWindowStart % WindowSize;
                        ackByte = NetPacket.UserDataHeaderSize + ackIdx / BitsInByte;
                        ackBit  = ackIdx % BitsInByte;

                        _ackPacket.RawData[ackByte] &= (byte)~(1 << ackBit);
                        _remoteWindowStart           = (_remoteWindowStart + 1) % NetPacket.MaxSequence;
                    }
                }

                _sendAcks = true;

                ackIdx  = seq % WindowSize;
                ackByte = NetPacket.UserDataHeaderSize + ackIdx / BitsInByte;
                ackBit  = ackIdx % BitsInByte;
                if ((_ackPacket.RawData[ackByte] & (1 << ackBit)) != 0)
                {
#if RELIABLE_LOG
                    Console.WriteLine($"rudp ReliableInOrder duplicate");
#endif
                    NetPool.PacketPool.Free(poolingPacket);
                    return(false);
                }

                _ackPacket.RawData[ackByte] |= (byte)(1 << ackBit);
            }

            if (seq == _remoteSequence)
            {
                _udpChannel.PacketReceived?.Invoke(_udpChannel, poolingPacket);

                _remoteSequence = (_remoteSequence + 1) % NetPacket.MaxSequence;

                if (_ordered)
                {
                    NetPacket p;
                    while ((p = _receivedPackets[_remoteSequence % WindowSize]) != null)
                    {
                        _receivedPackets[_remoteSequence % WindowSize] = null;
                        _udpChannel.PacketReceived?.Invoke(_udpChannel, p);
                        _remoteSequence = (_remoteSequence + 1) % NetPacket.MaxSequence;
                    }
                }
                else
                {
                    while (_earlyReceived[_remoteSequence % WindowSize])
                    {
                        _earlyReceived[_remoteSequence % WindowSize] = false;
                        _remoteSequence = (_remoteSequence + 1) % NetPacket.MaxSequence;
                    }
                }

                return(true);
            }

            if (_ordered)
            {
                _receivedPackets[ackIdx] = poolingPacket;
            }
            else
            {
                _earlyReceived[ackIdx] = true;
                _udpChannel.PacketReceived?.Invoke(_udpChannel, poolingPacket);
            }

            return(true);
        }
Ejemplo n.º 4
0
        private void ProcessAck(NetPacket packet)
        {
            if (packet.Size != _ackPacket.Size)
            {
#if RELIABLE_LOG
                Console.WriteLine("rudp Invalid acks packet size");
#endif
                return;
            }

            byte[] acksData = packet.RawData;
            lock (_pendingPackets)
            {
                ushort ackWindowStart = packet.Sequence;
                int    windowRel      = NetUtil.RelativeSequenceNumber(_localWindowStart, ackWindowStart);
                if (ackWindowStart >= NetPacket.MaxSequence || windowRel < 0)
                {
#if RELIABLE_LOG
                    Console.WriteLine($"rudp Bad window start {ackWindowStart} {windowRel}");
#endif
                    return;
                }

                if (windowRel >= WindowSize)
                {
#if RELIABLE_LOG
                    Console.WriteLine("rudp Old acks");
#endif
                    return;
                }

                for (int pendingSeq = _localWindowStart;
                     pendingSeq != _localSequence;
                     pendingSeq = (pendingSeq + 1) % NetPacket.MaxSequence)
                {
                    int rel = NetUtil.RelativeSequenceNumber(pendingSeq, ackWindowStart);
                    if (rel >= WindowSize)
                    {
#if RELIABLE_LOG
                        Console.WriteLine($"[PA]REL: {rel} {pendingSeq} {_localSequence} {ackWindowStart}");
#endif
                        break;
                    }

                    int pendingIdx  = pendingSeq % WindowSize;
                    int currentByte = NetPacket.UserDataHeaderSize + pendingIdx / BitsInByte;
                    int currentBit  = pendingIdx % BitsInByte;
                    if ((acksData[currentByte] & (1 << currentBit)) == 0)
                    {
                        Interlocked.Increment(ref _statistic.UdpPacketLossCount);
#if RELIABLE_LOG
                        Console.WriteLine($"[PA]False ack: {pendingSeq}");
#endif
                        continue;
                    }
                    if (pendingSeq == _localWindowStart)
                    {
                        _localWindowStart = (_localWindowStart + 1) % NetPacket.MaxSequence;
                    }
#if RELIABLE_LOG
                    Console.WriteLine($"ProcessAck End Id : {pendingIdx}");
#endif
                    _pendingPackets[pendingIdx].Clear();
                }
            }
        }
Ejemplo n.º 5
0
        public bool SendPendingPacket()
        {
            // 응답패킷을 보내야 한다면
            if (_sendAcks == true)
            {
                // lock에 비용이 많이드므로 먼저 체크한번 하고 나중에 또 체크하자
                lock (_ackPacket)
                {
                    if (_sendAcks == true)
                    {
                        _sendAcks = false;

                        IPacketFilter filter = _channelOption.PacketFilter;
                        if (filter != null)
                        {
                            var poolingPacket = NetPool.PacketPool.Alloc(_ackPacket, 0);
                            try
                            {
                                while (filter != null)
                                {
                                    poolingPacket = filter.Encode(poolingPacket);
                                    filter        = filter.NextFilter;
                                }

                                _udpChannel.SendTo(poolingPacket.RawData, 0, poolingPacket.Size, UdpChannel.SendMode.Buffered);
                            }
                            finally
                            {
                                NetPool.PacketPool.Free(poolingPacket);
                            }
                        }
                        else
                        {
                            _udpChannel.SendTo(_ackPacket.RawData, 0, _ackPacket.Size, UdpChannel.SendMode.Buffered);
                        }
                    }
                }
            }

            lock (_pendingPackets)
            {
                long nowTicks = DateTime.UtcNow.Ticks;

                lock (_sendQueue)
                {
                    while (_sendQueue.Count > 0)
                    {
                        int relate = NetUtil.RelativeSequenceNumber(_localSequence, _localWindowStart);
                        if (relate >= WindowSize)
                        {
                            break;
                        }

                        NetPacket packet = _sendQueue.Dequeue();

                        packet.Sequence = (ushort)_localSequence;
                        _pendingPackets[_localSequence % WindowSize].Init(packet, nowTicks);
                        _localSequence = (_localSequence + 1) % NetPacket.MaxSequence;
                    }
                }

                for (int pendingSeq = _localWindowStart; pendingSeq != _localSequence; pendingSeq = (pendingSeq + 1) % NetPacket.MaxSequence)
                {
                    if (_pendingPackets[pendingSeq % WindowSize].TrySend(
                            nowTicks,
                            _channelOption.RudpDisconnectTimeout,
                            _udpChannel,
                            _statistic) == false)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }