Exemple #1
0
        public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool reuseAddress)
        {
            _udpSocketv4                   = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _udpSocketv4.Blocking          = false;
            _udpSocketv4.ReceiveBufferSize = NetConstants.SocketBufferSize;
            _udpSocketv4.SendBufferSize    = NetConstants.SocketBufferSize;
            _udpSocketv4.Ttl               = NetConstants.SocketTTL;
            if (reuseAddress)
            {
                _udpSocketv4.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            }
#if !NETCORE
            _udpSocketv4.DontFragment = true;
#endif
            try
            {
                _udpSocketv4.EnableBroadcast = true;
            }
            catch (SocketException e)
            {
                NetUtils.DebugWriteError("Broadcast error: {0}", e.ToString());
            }

            if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port)))
            {
                return(false);
            }
            LocalPort              = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port;
            _running               = true;
            _threadv4              = new Thread(ReceiveLogic);
            _threadv4.Name         = "SocketThreadv4(" + LocalPort + ")";
            _threadv4.IsBackground = true;
            _threadv4.Start(_udpSocketv4);

            //Check IPv6 support
            if (!IPv6Support)
            {
                return(true);
            }

            _udpSocketv6                   = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
            _udpSocketv6.Blocking          = false;
            _udpSocketv6.ReceiveBufferSize = NetConstants.SocketBufferSize;
            _udpSocketv6.SendBufferSize    = NetConstants.SocketBufferSize;
            //_udpSocketv6.Ttl = NetConstants.SocketTTL;
            if (reuseAddress)
            {
                _udpSocketv6.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            }

            //Use one port for two sockets
            if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort)))
            {
                try
                {
#if !ENABLE_IL2CPP
                    _udpSocketv6.SetSocketOption(
                        SocketOptionLevel.IPv6,
                        SocketOptionName.AddMembership,
                        new IPv6MulticastOption(MulticastAddressV6));
#endif
                }
                catch (Exception)
                {
                    // Unity3d throws exception - ignored
                }

                _threadv6              = new Thread(ReceiveLogic);
                _threadv6.Name         = "SocketThreadv6(" + LocalPort + ")";
                _threadv6.IsBackground = true;
                _threadv6.Start(_udpSocketv6);
            }

            return(true);
        }
Exemple #2
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            _timeSinceLastPacket = 0;

            NetUtils.DebugWrite("[RR]PacketProperty: {0}", packet.Property);
            switch (packet.Property)
            {
            case PacketProperty.ConnectRequest:
                //response with connect
                SendConnectAccept();
                _packetPool.Recycle(packet);
                break;

            case PacketProperty.Merged:
                int pos = NetConstants.HeaderSize;
                while (pos < packet.Size)
                {
                    ushort size = BitConverter.ToUInt16(packet.RawData, pos);
                    pos += 2;
                    NetPacket mergedPacket = _packetPool.GetPacket(size, false);
                    if (!mergedPacket.FromBytes(packet.RawData, pos, size))
                    {
                        _packetPool.Recycle(packet);
                        break;
                    }
                    pos += size;
                    ProcessPacket(mergedPacket);
                }
                break;

            //If we get ping, send pong
            case PacketProperty.Ping:
                if (NetUtils.RelativeSequenceNumber(packet.Sequence, _remotePingSequence) < 0)
                {
                    _packetPool.Recycle(packet);
                    break;
                }
                NetUtils.DebugWrite("[PP]Ping receive, send pong");
                _remotePingSequence = packet.Sequence;
                _packetPool.Recycle(packet);

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

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

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

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

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

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

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

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

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

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

            case PacketProperty.ShutdownOk:
            case PacketProperty.Disconnect:
                _connectionState = ConnectionState.Disconnected;
                _packetPool.Recycle(packet);
                break;

            default:
                NetUtils.DebugWriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
Exemple #3
0
        private void DataReceived(byte[] reusableBuffer, int count, IPEndPoint remoteEndPoint)
        {
#if STATS_ENABLED
            Statistics.PacketsReceived++;
            Statistics.BytesReceived += (uint)count;
#endif

            //Try read packet
            NetPacket packet = NetPacketPool.GetPacket(count, false);
            if (!packet.FromBytes(reusableBuffer, 0, count))
            {
                NetPacketPool.Recycle(packet);
                NetUtils.DebugWriteError("[NM] DataReceived: bad!");
                return;
            }

            //Check unconnected
            switch (packet.Property)
            {
            case PacketProperty.DiscoveryRequest:
                if (DiscoveryEnabled)
                {
                    var netEvent = CreateEvent(NetEventType.DiscoveryRequest);
                    netEvent.RemoteEndPoint = remoteEndPoint;
                    netEvent.DataReader.SetSource(packet.RawData, NetConstants.HeaderSize, count);
                    EnqueueEvent(netEvent);
                }
                return;

            case PacketProperty.DiscoveryResponse:
            {
                var netEvent = CreateEvent(NetEventType.DiscoveryResponse);
                netEvent.RemoteEndPoint = remoteEndPoint;
                netEvent.DataReader.SetSource(packet.RawData, NetConstants.HeaderSize, count);
                EnqueueEvent(netEvent);
            }
                return;

            case PacketProperty.UnconnectedMessage:
                if (UnconnectedMessagesEnabled)
                {
                    var netEvent = CreateEvent(NetEventType.ReceiveUnconnected);
                    netEvent.RemoteEndPoint = remoteEndPoint;
                    netEvent.DataReader.SetSource(packet.RawData, NetConstants.HeaderSize, count);
                    EnqueueEvent(netEvent);
                }
                return;

            case PacketProperty.NatIntroduction:
            case PacketProperty.NatIntroductionRequest:
            case PacketProperty.NatPunchMessage:
            {
                if (NatPunchEnabled)
                {
                    NatPunchModule.ProcessMessage(remoteEndPoint, packet);
                }
                return;
            }
            }

            //Check normal packets
            NetPeer netPeer;
            bool    isPeerConnecting;
            lock (connectingPeers)
            {
                isPeerConnecting = connectingPeers.Contains(remoteEndPoint);
                peers.TryGetValue(remoteEndPoint, out netPeer);
            }

            if (netPeer != null)
            {
                if (netPeer.ConnectionState == ConnectionState.Disconnected)
                {
                    return;
                }
                NetEvent netEvent;
                switch (packet.Property)
                {
                case PacketProperty.Disconnect:
                    if (netPeer.ConnectionState == ConnectionState.InProgress ||
                        netPeer.ConnectionState == ConnectionState.Connected)
                    {
                        if (BitConverter.ToInt64(packet.RawData, 1) != netPeer.ConnectId)
                        {
                            //Old or incorrect disconnect
                            NetPacketPool.Recycle(packet);
                            return;
                        }
                        netEvent      = CreateEvent(NetEventType.Disconnect);
                        netEvent.Peer = netPeer;
                        netEvent.DataReader.SetSource(packet.RawData, 9, packet.Size);
                        netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose;
                        EnqueueEvent(netEvent);
                        netPeer.ProcessPacket(packet);
                        SendRaw(new[] { (byte)PacketProperty.ShutdownOk }, 0, 1, remoteEndPoint);
                    }
                    return;

                case PacketProperty.ConnectAccept:
                    if (netPeer.ProcessConnectAccept(packet))
                    {
                        var connectEvent = CreateEvent(NetEventType.Connect);
                        connectEvent.Peer = netPeer;
                        EnqueueEvent(connectEvent);
                    }
                    return;

                case PacketProperty.ConnectRequest:
                    long newId = BitConverter.ToInt64(packet.RawData, NetConstants.RequestConnectIdIndex);
                    NetUtils.DebugWrite("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", netPeer.ConnectId, newId, remoteEndPoint);

                    //Remove old peer and connect new
                    if (newId > netPeer.ConnectId)
                    {
                        netEvent      = CreateEvent(NetEventType.Disconnect);
                        netEvent.Peer = netPeer;
                        netEvent.DataReader.SetSource(packet.RawData, 9, packet.Size);
                        netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose;
                        peers.RemovePeer(netPeer);
                        break;
                        //To reconnect peer
                    }
                    else
                    {
                        //Just answer accept
                        netPeer.ProcessPacket(packet);
                        return;
                    }

                default:
                    netPeer.ProcessPacket(packet);
                    return;
                }
            }

            //Unacked shutdown
            if (packet.Property == PacketProperty.Disconnect)
            {
                SendRaw(new[] { (byte)PacketProperty.ShutdownOk }, 0, 1, remoteEndPoint);
                return;
            }

            if (packet.Property == PacketProperty.ConnectRequest && packet.Size >= 12)
            {
                NetUtils.DebugWrite("[NM] Received ConnectionRequest");
                if (isPeerConnecting)
                {
                    NetUtils.DebugWrite("[NM] Peer already connecting");
                    return;
                }
                if (GetPeersCount(ConnectionState.Connected | ConnectionState.InProgress) < maxConnections)
                {
                    int protoId = BitConverter.ToInt32(packet.RawData, 1);
                    if (protoId != NetConstants.ProtocolId)
                    {
                        NetUtils.DebugWrite(ConsoleColor.Cyan,
                                            "[NM] Peer connect reject. Invalid protocol ID: " + protoId);
                        return;
                    }

                    //Getting new id for peer
                    long connectionId = BitConverter.ToInt64(packet.RawData, 5);

                    // Read data and create request
                    var reader = new NetDataReader(null, 0, 0);
                    if (packet.Size > 12)
                    {
                        reader.SetSource(packet.RawData, 13, packet.Size);
                    }

                    NetUtils.DebugWrite("[NM] Creating request event: " + connectionId);
                    lock (connectingPeers)
                    {
                        connectingPeers.Add(remoteEndPoint);
                    }
                    var netEvent = CreateEvent(NetEventType.ConnectionRequest);
                    netEvent.ConnectionRequest =
                        new ConnectionRequest(connectionId, remoteEndPoint, reader, OnConnectionSolved);
                    EnqueueEvent(netEvent);
                }
            }
        }
Exemple #4
0
        internal void AddIncomingPacket(NetPacket p)
        {
            if (p.IsFragmented)
            {
                NetUtils.DebugWrite("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal);
                //Get needed array from dictionary
                ushort            packetFragId = p.FragmentId;
                IncomingFragments incomingFragments;
                if (!_holdedFragments.TryGetValue(packetFragId, out incomingFragments))
                {
                    incomingFragments = new IncomingFragments
                    {
                        Fragments = new NetPacket[p.FragmentsTotal]
                    };
                    _holdedFragments.Add(packetFragId, incomingFragments);
                }

                //Cache
                var fragments = incomingFragments.Fragments;

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

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

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

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

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

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

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

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

                //Clear memory
                _packetPool.Recycle(resultingPacket);
                _holdedFragments.Remove(packetFragId);
            }
            else //Just simple packet
            {
                _netManager.ReceiveFromPeer(p, _remoteEndPoint);
                _packetPool.Recycle(p);
            }
        }