Static class for defining your own LiteNetLib logger instead of Console.WriteLine or Debug.Log if compiled with UNITY flag
예제 #1
0
        internal bool Shutdown(byte[] data, int start, int length, bool force)
        {
            lock (_shutdownLock)
            {
                //trying to shutdown already disconnected
                if (_connectionState == ConnectionState.Disconnected ||
                    _connectionState == ConnectionState.ShutdownRequested)
                {
                    return(false);
                }

                //don't send anything
                if (force)
                {
                    _connectionState = ConnectionState.Disconnected;
                    return(true);
                }

                //reset time for reconnect protection
                _timeSinceLastPacket = 0;

                //send shutdown packet
                _shutdownPacket = new NetPacket(PacketProperty.Disconnect, length);
                _shutdownPacket.ConnectionNumber = _connectNum;
                FastBitConverter.GetBytes(_shutdownPacket.RawData, 1, _connectTime);
                if (_shutdownPacket.Size >= _mtu)
                {
                    //Drop additional data
                    NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU - 8!");
                }
                else if (data != null && length > 0)
                {
                    Buffer.BlockCopy(data, start, _shutdownPacket.RawData, 9, length);
                }
                _connectionState = ConnectionState.ShutdownRequested;
                NetDebug.Write("[Peer] Send disconnect");
                NetManager.SendRaw(_shutdownPacket, EndPoint);
                return(true);
            }
        }
예제 #2
0
        private void ReceiveLogic(object state)
        {
            Socket   socket         = (Socket)state;
            EndPoint bufferEndPoint = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);

            while (IsActive())
            {
                //Reading data
                try
                {
                    if (socket.Available == 0 && !socket.Poll(ReceivePollingTime, SelectMode.SelectRead))
                    {
                        continue;
                    }
                    NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize);
                    packet.Size = socket.ReceiveFrom(packet.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None,
                                                     ref bufferEndPoint);

                    //NetDebug.Write(NetLogLevel.Trace, $"[R]Received data from {bufferEndPoint}, result: {packet.Size}");
                    OnMessageReceived(packet, (IPEndPoint)bufferEndPoint);
                }
                catch (SocketException ex)
                {
                    if (ProcessError(ex))
                    {
                        return;
                    }
                }
                catch (ObjectDisposedException)
                {
                    //socket closed
                    return;
                }
                catch (Exception e)
                {
                    //protects socket receive thread
                    NetDebug.WriteError("[NM] SocketReceiveThread error: " + e);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Flush all queued packets
        /// </summary>
        public void Flush()
        {
            if (_connectionState != ConnectionState.Connected)
            {
                return;
            }
            lock (_flushLock)
            {
                _reliableOrderedChannel.SendNextPackets();
                _reliableUnorderedChannel.SendNextPackets();
                _reliableSequencedChannel.SendNextPackets();
                _sequencedChannel.SendNextPackets();
                _unreliableChannel.SendNextPackets();

                //If merging enabled
                if (_mergePos > 0)
                {
                    if (_mergeCount > 1)
                    {
                        NetDebug.Write("[P]Send merged: " + _mergePos + ", count: " + _mergeCount);
                        _netManager.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, _remoteEndPoint);
#if STATS_ENABLED
                        Statistics.PacketsSent++;
                        Statistics.BytesSent += (ulong)(NetConstants.HeaderSize + _mergePos);
#endif
                    }
                    else
                    {
                        //Send without length information and merging
                        _netManager.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, _remoteEndPoint);
#if STATS_ENABLED
                        Statistics.PacketsSent++;
                        Statistics.BytesSent += (ulong)(_mergePos - 2);
#endif
                    }
                    _mergePos   = 0;
                    _mergeCount = 0;
                }
            }
        }
예제 #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
            _socket.Ttl = 2;
            _socket.SendRaw(new[] { (byte)PacketProperty.Empty }, 0, 1, req.External);

            // 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);
        }
예제 #5
0
        private void ReceiveLogic(object state)
        {
            Socket   socket         = (Socket)state;
            EndPoint bufferEndPoint = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);

            byte[] receiveBuffer = new byte[NetConstants.MaxPacketSize];

            while (IsActive())
            {
                int result;

                //Reading data
                try
                {
                    if (socket.Available == 0 && !socket.Poll(ReceivePollingTime, SelectMode.SelectRead))
                    {
                        continue;
                    }
                    result = socket.ReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None,
                                                ref bufferEndPoint);
                }
                catch (SocketException ex)
                {
                    if (ProcessError(ex, bufferEndPoint))
                    {
                        return;
                    }
                    continue;
                }
                catch (ObjectDisposedException)
                {
                    return;
                }

                //All ok!
                NetDebug.Write(NetLogLevel.Trace, "[R]Received data from {0}, result: {1}", bufferEndPoint.ToString(), result);
                _listener.OnMessageReceived(receiveBuffer, result, 0, (IPEndPoint)bufferEndPoint);
            }
        }
예제 #6
0
 public NetPeer AcceptIfKey(string key)
 {
     if (!TryActivate())
     {
         return(null);
     }
     try
     {
         if (Data.GetString() == key)
         {
             Result = ConnectionRequestResult.Accept;
             return(_listener.OnConnectionSolved(this, null, 0, 0));
         }
     }
     catch
     {
         NetDebug.WriteError("[AC] Invalid incoming data");
     }
     Result = ConnectionRequestResult.Reject;
     _listener.OnConnectionSolved(this, null, 0, 0);
     return(null);
 }
        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);
                }
            }
        }
예제 #8
0
        internal void SendUserData(NetPacket packet)
        {
            packet.ConnectionNumber = _connectNum;
            //2 - merge byte + minimal packet size + datalen(ushort)
            if (_netManager.MergeEnabled && _mergePos + packet.Size + NetConstants.HeaderSize * 2 + 2 < _mtu)
            {
                FastBitConverter.GetBytes(_mergeData.RawData, _mergePos + NetConstants.HeaderSize, (ushort)packet.Size);
                Buffer.BlockCopy(packet.RawData, 0, _mergeData.RawData, _mergePos + NetConstants.HeaderSize + 2, packet.Size);
                _mergePos += packet.Size + 2;
                _mergeCount++;

                //DebugWriteForce("Merged: " + _mergePos + "/" + (_mtu - 2) + ", count: " + _mergeCount);
                return;
            }

            NetDebug.Write(NetLogLevel.Trace, "[P]SendingPacket: " + packet.Property);
            _netManager.SendRaw(packet, _remoteEndPoint);
#if STATS_ENABLED
            Statistics.PacketsSent++;
            Statistics.BytesSent += (ulong)packet.Size;
#endif
        }
예제 #9
0
            //Returns true if there is a pending packet inside
            public bool TrySend(long currentTime, NetPeer peer)
            {
                if (_packet == null)
                {
                    return(false);
                }

                if (_isSent) //check send time
                {
                    double resendDelay    = peer.ResendDelay * TimeSpan.TicksPerMillisecond;
                    double packetHoldTime = currentTime - _timeStamp;
                    if (packetHoldTime < resendDelay)
                    {
                        return(true);
                    }
                    NetDebug.Write("[RC]Resend: {0} > {1}", (int)packetHoldTime, resendDelay);
                }
                _timeStamp = currentTime;
                _isSent    = true;
                peer.SendUserData(_packet);
                return(true);
            }
예제 #10
0
        private void HandleNatIntroduction(NetDataReader dr)
        {
            // read intro
            byte       hostByte       = dr.GetByte();
            IPEndPoint remoteInternal = dr.GetNetEndPoint();
            IPEndPoint remoteExternal = dr.GetNetEndPoint();
            string     token          = dr.GetString(MaxTokenLength);

            NetDebug.Write(NetLogLevel.Trace, "[NAT] introduction received; we are designated " + (hostByte == HostByte ? "host" : "client"));
            NetDataWriter writer = new NetDataWriter();

            // send internal punch
            writer.Put((byte)PacketProperty.NatPunchMessage);
            writer.Put(hostByte);
            writer.Put(token);
            SocketError errorCode = 0;

            _socket.SendTo(writer.Data, 0, writer.Length, remoteInternal, ref errorCode);
            NetDebug.Write(NetLogLevel.Trace, "[NAT] internal punch sent to " + remoteInternal);

            // send external punch
            writer.Reset();
            writer.Put((byte)PacketProperty.NatPunchMessage);
            writer.Put(hostByte);
            writer.Put(token);
            if (hostByte == HostByte)
            {
                _socket.Ttl = 2;
                _socket.SendTo(writer.Data, 0, writer.Length, remoteExternal, ref errorCode);
                _socket.Ttl = NetConstants.SocketTTL;
            }
            else
            {
                _socket.SendTo(writer.Data, 0, writer.Length, remoteExternal, ref errorCode);
            }

            NetDebug.Write(NetLogLevel.Trace, "[NAT] external punch sent to " + remoteExternal);
        }
예제 #11
0
            //Returns true if there is a pending packet inside
            public bool TrySend(DateTime currentTime, NetPeer peer)
            {
                if (_packet == null)
                {
                    return(false);
                }

                if (_isSent) //check send time
                {
                    TimeSpan resendDelay    = peer.ResendDelay;
                    TimeSpan packetHoldTime = currentTime - _timeStamp;
                    if (packetHoldTime < resendDelay)
                    {
                        return(true);
                    }

                    NetDebug.Write("[RC]Resend: {0} > {1}", packetHoldTime, resendDelay);
                }
                _timeStamp = currentTime;
                _isSent    = true;
                peer.SendUserData(_packet);
                return(true);
            }
예제 #12
0
        private void HandleNatPunch(IPEndPoint senderEndPoint, NetDataReader dr)
        {
            byte fromHostByte = dr.GetByte();

            if (fromHostByte != HostByte && fromHostByte != ClientByte)
            {
                //garbage
                return;
            }

            //Read info
            string additionalInfo = dr.GetString(MaxTokenLength);

            NetDebug.Write(NetLogLevel.Trace, "[NAT] punch received from {0} - additional info: {1}", senderEndPoint, additionalInfo);

            //Release punch success to client; enabling him to Connect() to msg.Sender if token is ok
            lock (_successEvents)
            {
                _successEvents.Enqueue(new SuccessEventData {
                    TargetEndPoint = senderEndPoint, Token = additionalInfo
                });
            }
        }
예제 #13
0
파일: NetSocket.cs 프로젝트: beef331/rpg
        public int SendTo(byte[] data, int offset, int size, IPEndPoint remoteEndPoint, ref SocketError errorCode)
        {
            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);
            }
        }
        public bool SendBroadcast(byte[] data, int offset, int size, int port)
        {
            if (!IsActive())
            {
                return(false);
            }
            var broadcastSuccess = false;
            var multicastSuccess = false;

            try
            {
                broadcastSuccess = _udpSocketv4.SendTo(
                    data,
                    offset,
                    size,
                    SocketFlags.None,
                    new IPEndPoint(IPAddress.Broadcast, port)) > 0;

                if (_udpSocketv6 != null)
                {
                    multicastSuccess = _udpSocketv6.SendTo(
                        data,
                        offset,
                        size,
                        SocketFlags.None,
                        new IPEndPoint(MulticastAddressV6, port)) > 0;
                }
            }
            catch (Exception ex)
            {
                NetDebug.WriteError("[S][MCAST]" + ex);
                return(broadcastSuccess);
            }

            return(broadcastSuccess || multicastSuccess);
        }
예제 #15
0
        private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress)
        {
            //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)
            {
                socket.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);
                }
            }

            //Bind
            try
            {
                socket.Bind(ep);
                NetDebug.Write(NetLogLevel.Trace, "[B]Successfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
            }
            catch (SocketException bindException)
            {
                switch (bindException.SocketErrorCode)
                {
                //IPv6 bind fix
                case SocketError.AddressAlreadyInUse:
                    if (socket.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        try
                        {
                            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);
        }
예제 #16
0
        internal int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEndPoint)
        {
            if (!IsRunning)
            {
                return(0);
            }

            NetPacket expandedPacket = null;

            if (_extraPacketLayer != null)
            {
                expandedPacket = PoolGetPacket(length + _extraPacketLayer.ExtraPacketSizeForLayer);
                Buffer.BlockCopy(message, start, expandedPacket.RawData, 0, length);
                start = 0;
                _extraPacketLayer.ProcessOutBoundPacket(ref remoteEndPoint, ref expandedPacket.RawData, ref start, ref length);
                message = expandedPacket.RawData;
            }

            var socket = _udpSocketv4;

            if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support)
            {
                socket = _udpSocketv6;
                if (socket == null)
                {
                    return(0);
                }
            }

            int result;

            try
            {
                if (UseNativeSockets)
                {
                    byte[] socketAddress;

                    if (remoteEndPoint is NativeEndPoint nep)
                    {
                        socketAddress = nep.NativeAddress;
                    }
                    else //Convert endpoint to raw
                    {
                        if (_endPointBuffer == null)
                        {
                            _endPointBuffer = new byte[NativeSocket.IPv6AddrSize];
                        }
                        socketAddress = _endPointBuffer;

                        bool  ipv4          = remoteEndPoint.AddressFamily == AddressFamily.InterNetwork;
                        short addressFamily = NativeSocket.GetNativeAddressFamily(remoteEndPoint);

                        socketAddress[0] = (byte)(addressFamily);
                        socketAddress[1] = (byte)(addressFamily >> 8);
                        socketAddress[2] = (byte)(remoteEndPoint.Port >> 8);
                        socketAddress[3] = (byte)(remoteEndPoint.Port);

                        if (ipv4)
                        {
#pragma warning disable 618
                            long addr = remoteEndPoint.Address.Address;
#pragma warning restore 618
                            socketAddress[4] = (byte)(addr);
                            socketAddress[5] = (byte)(addr >> 8);
                            socketAddress[6] = (byte)(addr >> 16);
                            socketAddress[7] = (byte)(addr >> 24);
                        }
                        else
                        {
#if NETCOREAPP || NETSTANDARD2_1 || NETSTANDARD2_1_OR_GREATER
                            remoteEndPoint.Address.TryWriteBytes(new Span <byte>(socketAddress, 8, 16), out _);
#else
                            byte[] addrBytes = remoteEndPoint.Address.GetAddressBytes();
                            Buffer.BlockCopy(addrBytes, 0, socketAddress, 8, 16);
#endif
                        }
                    }

#if LITENETLIB_UNSAFE
                    unsafe
                    {
                        fixed(byte *dataWithOffset = &message[start])
                        {
                            result =
                                NativeSocket.SendTo(socket.Handle, dataWithOffset, length, socketAddress, socketAddress.Length);
                        }
                    }
#else
                    if (start > 0)
                    {
                        if (_sendToBuffer == null)
                        {
                            _sendToBuffer = new byte[NetConstants.MaxPacketSize];
                        }
                        Buffer.BlockCopy(message, start, _sendToBuffer, 0, length);
                        message = _sendToBuffer;
                    }

                    result = NativeSocket.SendTo(socket.Handle, message, length, socketAddress, socketAddress.Length);
#endif
                    if (result == -1)
                    {
                        throw NativeSocket.GetSocketException();
                    }
                }
                else
                {
                    result = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint);
                }
                //NetDebug.WriteForce("[S]Send packet to {0}, result: {1}", remoteEndPoint, result);
            }
            catch (SocketException ex)
            {
                switch (ex.SocketErrorCode)
                {
                case SocketError.NoBufferSpaceAvailable:
                case SocketError.Interrupted:
                    return(0);

                case SocketError.MessageSize:
                    NetDebug.Write(NetLogLevel.Trace, "[SRD] 10040, datalen: {0}", length);
                    return(0);

                case SocketError.HostUnreachable:
                case SocketError.NetworkUnreachable:
                    if (DisconnectOnUnreachable && TryGetPeer(remoteEndPoint, out var fromPeer))
                    {
                        DisconnectPeerForce(
                            fromPeer,
                            ex.SocketErrorCode == SocketError.HostUnreachable
                                    ? DisconnectReason.HostUnreachable
                                    : DisconnectReason.NetworkUnreachable,
                            ex.SocketErrorCode,
                            null);
                    }

                    CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: ex.SocketErrorCode);
                    return(-1);

                default:
                    NetDebug.WriteError($"[S] {ex}");
                    return(-1);
                }
            }
            catch (Exception ex)
            {
                NetDebug.WriteError($"[S] {ex}");
                return(0);
            }
            finally
            {
                if (expandedPacket != null)
                {
                    PoolRecycle(expandedPacket);
                }
            }

            if (result <= 0)
            {
                return(0);
            }

            if (EnableStatistics)
            {
                Statistics.IncrementPacketsSent();
                Statistics.AddBytesSent(length);
            }

            return(result);
        }
예제 #17
0
        private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress)
        {
            //Setup socket
            socket.ReceiveTimeout    = 500;
            socket.SendTimeout       = 500;
            socket.ReceiveBufferSize = NetConstants.SocketBufferSize;
            socket.SendBufferSize    = NetConstants.SocketBufferSize;
            try
            {
                //知识点1 在UDP通信过程中,如果客户端中途断开,服务器会收到一个SocketException,错
                //误ID为10054,描述是“远程主机强迫关闭了一个现有的连接”,紧接着的事就可怕了,UDP
                //服务终止监听,所有客户端都受到了影响。也就是说一个客户端引起的异常导致了整个系统的崩溃。
                //UDP是无连接的,可是当实际现场使用时,如果远程主机异常关闭,服务器则会抛出一个异常:远程主机强行关闭了一个连接
                //而一但这个异常抛出后,又没有及时处理,那么整个UDP服务都将崩溃而不能接收任何数据
                socket.IOControl(SioUdpConnreset, new byte[] { 0 }, null);
            }
            catch
            {
                //ignored
            }

            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)
            {
                socket.Ttl = NetConstants.SocketTTL;

#if NETSTANDARD2_0 || NETCOREAPP2_0
                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);
                }
            }

            //Bind
            try
            {
                socket.Bind(ep);
                NetDebug.Write(NetLogLevel.Trace, "[B]Successfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
            }
            catch (SocketException bindException)
            {
                switch (bindException.SocketErrorCode)
                {
                //IPv6 bind fix
                case SocketError.AddressAlreadyInUse:
                    if (socket.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        try
                        {
                            socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
                            socket.Bind(ep);
                        }
                        catch (SocketException ex)
                        {
                            NetDebug.WriteError("[B]Bind exception: {0}, errorCode: {1}", ex.ToString(), ex.SocketErrorCode);
                            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);
        }
예제 #18
0
        internal void AddIncomingPacket(NetPacket p)
        {
            if (p.IsFragmented)
            {
                NetDebug.Write("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal);
                //Get needed array from dictionary
                ushort            packetFragId = p.FragmentId;
                IncomingFragments incomingFragments;
                if (!_holdedFragments.TryGetValue(packetFragId, out incomingFragments))
                {
                    incomingFragments = new IncomingFragments
                    {
                        Fragments = new NetPacket[p.FragmentsTotal],
                        ChannelId = p.ChannelId
                    };
                    _holdedFragments.Add(packetFragId, incomingFragments);
                }

                //Cache
                var fragments = incomingFragments.Fragments;

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

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

                //Increase total size
                incomingFragments.TotalSize += p.Size - NetConstants.FragmentTotalSize;

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

                NetPacket resultingPacket = _packetPool.GetWithProperty(p.Property, incomingFragments.TotalSize);
                resultingPacket.ChannelId = incomingFragments.ChannelId;

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

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

                //Send to process
                NetManager.ReceiveFromPeer(resultingPacket, this);

                //Clear memory
                _holdedFragments.Remove(packetFragId);
            }
            else //Just simple packet
            {
                NetManager.ReceiveFromPeer(p, this);
            }
        }
예제 #19
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            //not initialized
            if (_connectionState == ConnectionState.Outgoing)
            {
                _packetPool.Recycle(packet);
                return;
            }
            if (packet.ConnectionNumber != _connectNum && packet.Property != PacketProperty.ShutdownOk) //without connectionNum
            {
                NetDebug.Write(NetLogLevel.Trace, "[RR]Old packet");
                _packetPool.Recycle(packet);
                return;
            }
            _timeSinceLastPacket = 0;

            NetDebug.Write("[RR]PacketProperty: {0}", packet.Property);
            switch (packet.Property)
            {
            case PacketProperty.Merged:
                int pos = NetConstants.HeaderSize;
                while (pos < packet.Size)
                {
                    ushort size = BitConverter.ToUInt16(packet.RawData, pos);
                    pos += 2;
                    NetPacket mergedPacket = _packetPool.GetPacket(size, 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, _pongPacket.Sequence) > 0)
                {
                    NetDebug.Write("[PP]Ping receive, send pong");
                    FastBitConverter.GetBytes(_pongPacket.RawData, 3, DateTime.UtcNow.Ticks);
                    _pongPacket.Sequence = packet.Sequence;
                    NetManager.SendRaw(_pongPacket, EndPoint);
                }
                _packetPool.Recycle(packet);
                break;

            //If we get pong, calculate ping time and rtt
            case PacketProperty.Pong:
                if (packet.Sequence == _pingPacket.Sequence)
                {
                    _pingTimer.Stop();
                    int elapsedMs = (int)_pingTimer.ElapsedMilliseconds;
                    _remoteDelta = BitConverter.ToInt64(packet.RawData, 3) + (elapsedMs * TimeSpan.TicksPerMillisecond) / 2 - DateTime.UtcNow.Ticks;
                    UpdateRoundTripTime(elapsedMs);
                    NetManager.ConnectionLatencyUpdated(this, elapsedMs / 2);
                    NetDebug.Write("[PP]Ping: {0} - {1} - {2}", packet.Sequence, elapsedMs, _remoteDelta);
                }
                _packetPool.Recycle(packet);
                break;

            case PacketProperty.Ack:
            case PacketProperty.Channeled:
                if (packet.ChannelId > _channels.Length)
                {
                    _packetPool.Recycle(packet);
                    break;
                }
                var channel = _channels[packet.ChannelId] ?? (packet.Property == PacketProperty.Ack ? null : CreateChannel(packet.ChannelId));
                if (channel != null)
                {
                    if (!channel.ProcessPacket(packet))
                    {
                        _packetPool.Recycle(packet);
                    }
                }
                break;

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

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

            case PacketProperty.ShutdownOk:
                if (_connectionState == ConnectionState.ShutdownRequested)
                {
                    _connectionState = ConnectionState.Disconnected;
                }
                _packetPool.Recycle(packet);
                break;

            default:
                NetDebug.WriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
예제 #20
0
        internal void Update(int deltaTime)
        {
            _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
            Flush();
        }
예제 #21
0
        private void SendInternal(
            byte[] data,
            int start,
            int length,
            byte channelNumber,
            DeliveryMethod deliveryMethod,
            object userData)
        {
            if (_connectionState == ConnectionState.ShutdownRequested ||
                _connectionState == ConnectionState.Disconnected)
            {
                return;
            }
            if (channelNumber >= _channels.Length)
            {
                return;
            }

            //Select channel
            PacketProperty property;
            BaseChannel    channel;

            if (deliveryMethod == DeliveryMethod.Unreliable)
            {
                property = PacketProperty.Unreliable;
                channel  = _unreliableChannel;
            }
            else
            {
                property = PacketProperty.Channeled;
                channel  = CreateChannel((byte)(channelNumber * 4 + (byte)deliveryMethod));
            }

            //Prepare
            NetDebug.Write("[RS]Packet: " + property);

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

            if (length + headerSize > mtu)
            {
                //if cannot be fragmented
                if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered)
                {
                    throw new TooBigPacketException("Unreliable packet size exceeded maximum of " + (_mtu - headerSize) + " bytes");
                }

                int packetFullSize = mtu - headerSize;
                int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize;
                int totalPackets   = length / packetDataSize + (length % packetDataSize == 0 ? 0 : 1);

                NetDebug.Write("FragmentSend:\n" +
                               " MTU: {0}\n" +
                               " headerSize: {1}\n" +
                               " packetFullSize: {2}\n" +
                               " packetDataSize: {3}\n" +
                               " totalPackets: {4}",
                               mtu, headerSize, packetFullSize, packetDataSize, totalPackets);

                if (totalPackets > ushort.MaxValue)
                {
                    throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue);
                }

                lock (_sendLock)
                {
                    for (ushort partIdx = 0; partIdx < totalPackets; partIdx++)
                    {
                        int sendLength = length > packetDataSize ? packetDataSize : length;

                        NetPacket p = _packetPool.GetWithProperty(property, sendLength + NetConstants.FragmentHeaderSize);
                        p.UserData       = userData;
                        p.FragmentId     = _fragmentId;
                        p.FragmentPart   = partIdx;
                        p.FragmentsTotal = (ushort)totalPackets;
                        p.MarkFragmented();


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

                        length -= sendLength;
                    }
                    _fragmentId++;
                }
                return;
            }

            //Else just send
            NetPacket packet = _packetPool.GetWithData(property, data, start, length);

            packet.UserData = userData;
            channel.AddToQueue(packet);
        }
예제 #22
0
        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 or ReliableSequenced packet size exceeded maximum of " + (mtu - headerSize) + " bytes, Check allowed size by GetMaxSinglePacketSize()");
                }

                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);
            }
        }
예제 #23
0
        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);
            }
        }
예제 #24
0
        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
            if (_channelSendQueue.Count > 0)
            {
                lock (_channelSendQueue)
                {
                    var count = _channelSendQueue.Count;
                    while (count-- > 0)
                    {
                        BaseChannel channel = _channelSendQueue.Dequeue();
                        if (channel.SendAndCheckQueue())
                        {
                            // still has something to send, re-add it to the send queue
                            _channelSendQueue.Enqueue(channel);
                        }
                    }
                }
            }

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

            SendMerged();
        }
예제 #25
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="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);
        }
예제 #26
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);
            }

            AddToPeerChannelSendQueue();

            //detailed check
            if (seq == _remoteSequence)
            {
                NetDebug.Write("[RR]ReliableInOrder packet succes");
                Peer.AddReliablePacket(_deliveryMethod, 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(_deliveryMethod, 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(_deliveryMethod, packet);
            }
            return(true);
        }
예제 #27
0
파일: NetSocket.cs 프로젝트: beef331/rpg
        private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress)
        {
            //Setup socket
            socket.ReceiveTimeout    = 500;
            socket.SendTimeout       = 500;
            socket.ReceiveBufferSize = NetConstants.SocketBufferSize;
            socket.SendBufferSize    = NetConstants.SocketBufferSize;
            try
            {
                socket.ExclusiveAddressUse = !reuseAddress;
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
            }
            catch
            {
                NetDebug.WriteError("IL2CPP SetSocketOption error");
            }
            if (socket.AddressFamily == AddressFamily.InterNetwork)
            {
                socket.Ttl = NetConstants.SocketTTL;

#if NETCORE
                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);
                }
            }

            //Bind
            try
            {
                socket.Bind(ep);
                NetDebug.Write(NetLogLevel.Trace, "[B]Successfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
            }
            catch (SocketException bindException)
            {
                switch (bindException.SocketErrorCode)
                {
                //IPv6 bind fix
                case SocketError.AddressAlreadyInUse:
                    if (socket.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        try
                        {
                            socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
                            socket.Bind(ep);
                        }
                        catch (SocketException ex)
                        {
                            NetDebug.WriteError("[B]Bind exception: {0}, errorCode: {1}", ex.ToString(), ex.SocketErrorCode);
                            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);
        }
예제 #28
0
파일: NetSocket.cs 프로젝트: NoDogsInc/Cube
        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 (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                try
                {
                    socket.IOControl(SioUdpConnreset, new byte[] { 0 }, null);
                }
                catch
                {
                    //ignored
                }
            }

            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 (ep.AddressFamily == AddressFamily.InterNetwork || ipv6Mode == IPv6Mode.DualMode)
            {
                Ttl = NetConstants.SocketTTL;

                try { socket.EnableBroadcast = true; }
                catch (SocketException e)
                {
                    NetDebug.WriteError($"[B]Broadcast error: {e.SocketErrorCode}");
                }

                if (ipv6Mode == IPv6Mode.DualMode)
                {
                    try { socket.DualMode = true; }
                    catch (Exception e)
                    {
                        NetDebug.WriteError($"[B]Bind exception (dualmode setting): {e}");
                    }
                }
                else if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    try { socket.DontFragment = true; }
                    catch (SocketException e)
                    {
                        NetDebug.WriteError($"[B]DontFragment error: {e.SocketErrorCode}");
                    }
                }
            }
            //Bind
            try
            {
                socket.Bind(ep);
                NetDebug.Write(NetLogLevel.Trace, $"[B]Successfully binded to port: {((IPEndPoint)socket.LocalEndPoint).Port}, AF: {socket.AddressFamily}");

                //join multicast
                if (ep.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    try
                    {
#if !UNITY_2018_3_OR_NEWER
                        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.DualMode = false;
                            socket.Bind(ep);
                        }
                        catch (SocketException ex)
                        {
                            //because its fixed in 2018_3
                            NetDebug.WriteError($"[B]Bind exception: {ex}, errorCode: {ex.SocketErrorCode}");
                            return(false);
                        }
                        return(true);
                    }
                    break;

                //hack for iOS (Unity3D)
                case SocketError.AddressFamilyNotSupported:
                    return(true);
                }
                NetDebug.WriteError($"[B]Bind exception: {bindException}, errorCode: {bindException.SocketErrorCode}");
                return(false);
            }
            return(true);
        }
예제 #29
0
파일: NetSocket.cs 프로젝트: NoDogsInc/Cube
        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;
                    if (socket == null)
                    {
                        return(0);
                    }
                }

                int result;
                if (_useNativeSockets)
                {
                    byte[] socketAddress;

                    if (remoteEndPoint is NativeEndPoint nep)
                    {
                        socketAddress = nep.NativeAddress;
                    }
                    else //Convert endpoint to raw
                    {
                        if (_endPointBuffer == null)
                        {
                            _endPointBuffer = new byte[NativeSocket.IPv6AddrSize];
                        }
                        socketAddress = _endPointBuffer;

                        bool  ipv4          = remoteEndPoint.AddressFamily == AddressFamily.InterNetwork;
                        short addressFamily = NativeSocket.GetNativeAddressFamily(remoteEndPoint);

                        socketAddress[0] = (byte)(addressFamily);
                        socketAddress[1] = (byte)(addressFamily >> 8);
                        socketAddress[2] = (byte)(remoteEndPoint.Port >> 8);
                        socketAddress[3] = (byte)(remoteEndPoint.Port);

                        if (ipv4)
                        {
#pragma warning disable 618
                            long addr = remoteEndPoint.Address.Address;
#pragma warning restore 618
                            socketAddress[4] = (byte)(addr);
                            socketAddress[5] = (byte)(addr >> 8);
                            socketAddress[6] = (byte)(addr >> 16);
                            socketAddress[7] = (byte)(addr >> 24);
                        }
                        else
                        {
#if NETCOREAPP || NETSTANDARD2_1 || NETSTANDARD2_1_OR_GREATER
                            remoteEndPoint.Address.TryWriteBytes(new Span <byte>(socketAddress, 8, 16), out _);
#else
                            byte[] addrBytes = remoteEndPoint.Address.GetAddressBytes();
                            Buffer.BlockCopy(addrBytes, 0, socketAddress, 8, 16);
#endif
                        }
                    }

#if LITENETLIB_UNSAFE
                    unsafe
                    {
                        fixed(byte *dataWithOffset = &data[offset])
                        {
                            result = NativeSocket.SendTo(socket.Handle, dataWithOffset, size, socketAddress, socketAddress.Length);
                        }
                    }
#else
                    if (offset > 0)
                    {
                        if (_sendToBuffer == null)
                        {
                            _sendToBuffer = new byte[NetConstants.MaxPacketSize];
                        }
                        Buffer.BlockCopy(data, offset, _sendToBuffer, 0, size);
                        data = _sendToBuffer;
                    }
                    result = NativeSocket.SendTo(socket.Handle, data, size, socketAddress, socketAddress.Length);
#endif
                    if (result == -1)
                    {
                        throw NativeSocket.GetSocketException();
                    }
                }
                else
                {
                    result = socket.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint);
                }
                //NetDebug.WriteForce("[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);
            }
        }
예제 #30
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);
                    }
                }
            }
        }