Beispiel #1
0
        public override void SendNextPackets()
        {
            if (_mustSendAcks)
            {
                _mustSendAcks = false;
                NetDebug.Write("[RR]SendAcks");
                lock (_outgoingAcks)
                    Peer.SendUserData(_outgoingAcks);
            }

            long currentTime = DateTime.UtcNow.Ticks;

            lock (_pendingPackets) {
                //get packets from queue
                lock (OutgoingQueue) {
                    while (OutgoingQueue.Count > 0)
                    {
                        int relate = NetUtils.RelativeSequenceNumber(_localSeqence, _localWindowStart);
                        if (relate >= _windowSize)
                        {
                            break;
                        }

                        var netPacket = OutgoingQueue.Dequeue();
                        netPacket.Sequence  = (ushort)_localSeqence;
                        netPacket.ChannelId = _id;
                        _pendingPackets[_localSeqence % _windowSize].Init(netPacket);
                        _localSeqence = (_localSeqence + 1) % NetConstants.MaxSequence;
                    }
                }

                //send
                for (int pendingSeq = _localWindowStart;
                     pendingSeq != _localSeqence;
                     pendingSeq = (pendingSeq + 1) % NetConstants.MaxSequence)
                {
                    _pendingPackets[pendingSeq % _windowSize].TrySend(currentTime, Peer);
                }
            }
        }
Beispiel #2
0
        public int SendTo(byte[] data, int offset, int size, IPEndPoint remoteEndPoint, ref SocketError errorCode)
        {
            if (!IsActive())
            {
                return(0);
            }
            try {
                var socket = _udpSocketv4;
                if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support)
                {
                    socket = _udpSocketv6;
                }
                int result = socket.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint);
                NetDebug.Write(NetLogLevel.Trace, "[S]Send packet to {0}, result: {1}", remoteEndPoint, result);
                return(result);
            }
            catch (SocketException ex) {
                switch (ex.SocketErrorCode)
                {
                case SocketError.NoBufferSpaceAvailable:
                case SocketError.Interrupted:
                    return(0);

                case SocketError.MessageSize:     //do nothing
                    break;

                default:
                    NetDebug.WriteError("[S]" + ex);
                    break;
                }

                errorCode = ex.SocketErrorCode;
                return(-1);
            }
            catch (Exception ex) {
                NetDebug.WriteError("[S]" + ex);
                return(-1);
            }
        }
Beispiel #3
0
 // ===========================================
 // Internal and debug log related stuff
 // ===========================================
 internal static void PrintInterfaceInfos()
 {
     NetDebug.WriteForce(NetLogLevel.Info, "IPv6Support: {0}", NetSocket.IPv6Support);
     try {
         foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
         {
             foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
             {
                 if (ip.Address.AddressFamily == AddressFamily.InterNetwork ||
                     ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
                 {
                     NetDebug.WriteForce(NetLogLevel.Info, "Interface: {0}, Type: {1}, Ip: {2}, OpStatus: {3}",
                                         ni.Name, ni.NetworkInterfaceType.ToString(), ip.Address.ToString(),
                                         ni.OperationalStatus.ToString());
                 }
             }
         }
     }
     catch (Exception e) {
         NetDebug.WriteForce(NetLogLevel.Info, "Error while getting interface infos: {0}", e.ToString());
     }
 }
Beispiel #4
0
        //We got introduce and must punch
        private void OnNatIntroductionResponse(NatIntroduceResponsePacket req)
        {
            NetDebug.Write(NetLogLevel.Trace, "[NAT] introduction received");

            // send internal punch
            var punchPacket = new NatPunchPacket {
                Token = req.Token
            };

            Send(punchPacket, req.Internal);
            NetDebug.Write(NetLogLevel.Trace, "[NAT] internal punch sent to " + req.Internal);

            // hack for some routers
            SocketError errorCode = 0;

            _socket.Ttl = 2;
            _socket.SendTo(new[] { (byte)PacketProperty.Empty }, 0, 1, req.External, ref errorCode);

            // send external punch
            _socket.Ttl            = NetConstants.SocketTTL;
            punchPacket.IsExternal = true;
            Send(punchPacket, req.External);
            NetDebug.Write(NetLogLevel.Trace, "[NAT] external punch sent to " + req.External);
        }
Beispiel #5
0
        //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.AddReliablePacket(_sendType, packet);
                _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;

                if (_ordered)
                {
                    NetPacket p;
                    while ((p = _receivedPackets[_remoteSequence % _windowSize]) != null)
                    {
                        //process holden packet
                        _receivedPackets[_remoteSequence % _windowSize] = null;
                        Peer.AddReliablePacket(_sendType, 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);
            }

            //holden packet
            if (_ordered)
            {
                _receivedPackets[ackIdx] = packet;
            }
            else
            {
                _earlyReceived[ackIdx] = true;
                Peer.AddReliablePacket(_sendType, packet);
            }

            return(true);
        }
Beispiel #6
0
        //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 (Peer.NetManager.EnableStatistics)
                        {
                            Peer.Statistics.IncrementPacketLoss();
                            Peer.NetManager.Statistics.IncrementPacketLoss();
                        }

                        //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);
                    }
                }
            }
        }
Beispiel #7
0
        private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress, IPv6Mode ipv6Mode)
        {
            //Setup socket
            socket.ReceiveTimeout    = 500;
            socket.SendTimeout       = 500;
            socket.ReceiveBufferSize = NetConstants.SocketBufferSize;
            socket.SendBufferSize    = NetConstants.SocketBufferSize;
#if !UNITY || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
#if NETSTANDARD || NETCOREAPP
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
#endif
            try {
                socket.IOControl(SioUdpConnreset, new byte[] { 0 }, null);
            }
            catch {
                //ignored
            }
#endif

            try {
                socket.ExclusiveAddressUse = !reuseAddress;
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
            }
            catch {
                //Unity with IL2CPP throws an exception here, it doesn't matter in most cases so just ignore it
            }

            if (socket.AddressFamily == AddressFamily.InterNetwork)
            {
                Ttl = NetConstants.SocketTTL;

#if NETSTANDARD || NETCOREAPP
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
#endif
                try {
                    socket.DontFragment = true;
                }
                catch (SocketException e) {
                    NetDebug.WriteError("[B]DontFragment error: {0}", e.SocketErrorCode);
                }

                try {
                    socket.EnableBroadcast = true;
                }
                catch (SocketException e) {
                    NetDebug.WriteError("[B]Broadcast error: {0}", e.SocketErrorCode);
                }
            }
            else //IPv6 specific
            {
                if (ipv6Mode == IPv6Mode.DualMode)
                {
                    try {
                        //Disable IPv6 only mode
                        socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
                    }
                    catch (Exception e) {
                        NetDebug.WriteError("[B]Bind exception (dualmode setting): {0}", e.ToString());
                    }
                }
            }

            //Bind
            try {
                socket.Bind(ep);
                NetDebug.Write(NetLogLevel.Trace, "[B]Successfully binded to port: {0}",
                               ((IPEndPoint)socket.LocalEndPoint).Port);

                //join multicast
                if (socket.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    try {
#if !UNITY
                        socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership,
                                               new IPv6MulticastOption(MulticastAddressV6));
#endif
                    }
                    catch (Exception) {
                        // Unity3d throws exception - ignored
                    }
                }
            }
            catch (SocketException bindException) {
                switch (bindException.SocketErrorCode)
                {
                //IPv6 bind fix
                case SocketError.AddressAlreadyInUse:
                    if (socket.AddressFamily == AddressFamily.InterNetworkV6 && ipv6Mode != IPv6Mode.DualMode)
                    {
                        try {
                            //Set IPv6Only
                            socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
                            socket.Bind(ep);
                        }
#if UNITY_2018_3_OR_NEWER
                        catch (SocketException ex)
                        {
                            //because its fixed in 2018_3
                            NetDebug.WriteError("[B]Bind exception: {0}, errorCode: {1}", ex.ToString(), ex.SocketErrorCode);
#else
                        catch (SocketException) {
#endif
                            return(false);
                        }

                        return(true);
                    }

                    break;

                //hack for iOS (Unity3D)
                case SocketError.AddressFamilyNotSupported:
                    return(true);
                }

                NetDebug.WriteError("[B]Bind exception: {0}, errorCode: {1}", bindException.ToString(),
                                    bindException.SocketErrorCode);
                return(false);
            }

            return(true);
        }