DebugWrite() приватный Метод

private DebugWrite ( ConsoleColor color, string str ) : void
color ConsoleColor
str string
Результат void
        internal void ReceiveFromPeer(NetPacket packet, IPEndPoint remoteEndPoint)
        {
            NetPeer fromPeer;

            if (!_peers.TryGetValue(remoteEndPoint, out fromPeer))
            {
                return;
            }

            NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received message");
            DeliveryMethod deliveryMethod;

            switch (packet.Property)
            {
            default:     //PacketProperty.Unreliable
                deliveryMethod = DeliveryMethod.Unreliable;
                break;

            case PacketProperty.ReliableUnordered:
                deliveryMethod = DeliveryMethod.ReliableUnordered;
                break;

            case PacketProperty.ReliableOrdered:
                deliveryMethod = DeliveryMethod.ReliableOrdered;
                break;

            case PacketProperty.Sequenced:
                deliveryMethod = DeliveryMethod.Sequenced;
                break;

            case PacketProperty.ReliableSequenced:
                deliveryMethod = DeliveryMethod.ReliableSequenced;
                break;
            }
            CreateEvent(NetEvent.EType.Receive, fromPeer, fromPeer.EndPoint, deliveryMethod: deliveryMethod, readerSource: packet);
        }
Пример #2
0
        /// <summary>
        /// Flush all queued packets
        /// </summary>
        public void Flush()
        {
            lock (_flushLock)
            {
                _reliableOrderedChannel.SendNextPackets();
                _reliableUnorderedChannel.SendNextPackets();
                _reliableSequencedChannel.SendNextPackets();
                _sequencedChannel.SendNextPackets();
                _unreliableChannel.SendNextPackets();

                //If merging enabled
                if (_mergePos > 0)
                {
                    if (_mergeCount > 1)
                    {
                        NetUtils.DebugWrite("[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;
                }
            }
        }
Пример #3
0
        internal NetPeer(NetManager peerListener, NetEndPoint remoteEndPoint, long connectId)
        {
            Statistics      = new NetStatistics();
            _packetPool     = peerListener.PacketPool;
            _peerListener   = peerListener;
            _remoteEndPoint = remoteEndPoint;

            _avgRtt        = 0;
            _rtt           = 0;
            _pingSendTimer = 0;

            _reliableOrderedChannel   = new ReliableChannel(this, true);
            _reliableUnorderedChannel = new ReliableChannel(this, false);
            _sequencedChannel         = new SequencedChannel(this);
            _simpleChannel            = new SimpleChannel(this);

            _holdedFragments = new Dictionary <ushort, IncomingFragments>();

            _mergeData = _packetPool.Get(PacketProperty.Merged, NetConstants.MaxPacketSize);

            //if ID != 0 then we already connected
            _connectAttempts = 0;
            if (connectId == 0)
            {
                _connectId = DateTime.UtcNow.Ticks;
                SendConnectRequest();
            }
            else
            {
                _connectId       = connectId;
                _connectionState = ConnectionState.Connected;
                SendConnectAccept();
            }

            NetUtils.DebugWrite(ConsoleColor.Cyan, "[CC] ConnectId: {0}", _connectId);
        }
Пример #4
0
        private void HandleNatIntroduction(NetDataReader dr)
        {
            // read intro
            byte        hostByte       = dr.GetByte();
            NetEndPoint remoteInternal = dr.GetNetEndPoint();
            NetEndPoint remoteExternal = dr.GetNetEndPoint();
            string      token          = dr.GetString(MaxTokenLength);

            NetUtils.DebugWrite(ConsoleColor.Cyan, "[NAT] introduction received; we are designated " + (hostByte == HostByte ? "host" : "client"));
            NetDataWriter writer = new NetDataWriter();

            // send internal punch
            writer.Put(hostByte);
            writer.Put(token);
            _socket.SendTo(NetPacket.CreateRawPacket(PacketProperty.NatPunchMessage, writer), remoteInternal);
            NetUtils.DebugWrite(ConsoleColor.Cyan, "[NAT] punch sent to " + remoteInternal);

            // send external punch
            writer.Reset();
            writer.Put(hostByte);
            writer.Put(token);
            _socket.SendTo(NetPacket.CreateRawPacket(PacketProperty.NatPunchMessage, writer), remoteExternal);
            NetUtils.DebugWrite(ConsoleColor.Cyan, "[NAT] punch sent to " + remoteExternal);
        }
Пример #5
0
        internal void ReceiveFromPeer(NetPacket packet, IPEndPoint remoteEndPoint)
        {
            NetPeer fromPeer;

            if (_peers.TryGetValue(remoteEndPoint, out fromPeer))
            {
                NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received message");
                var netEvent = CreateEvent(NetEventType.Receive);
                netEvent.Peer           = fromPeer;
                netEvent.RemoteEndPoint = fromPeer.EndPoint;
                switch (packet.Property)
                {
                case PacketProperty.Unreliable:
                    netEvent.DeliveryMethod = DeliveryMethod.Unreliable;
                    break;

                case PacketProperty.ReliableUnordered:
                    netEvent.DeliveryMethod = DeliveryMethod.ReliableUnordered;
                    break;

                case PacketProperty.ReliableOrdered:
                    netEvent.DeliveryMethod = DeliveryMethod.ReliableOrdered;
                    break;

                case PacketProperty.Sequenced:
                    netEvent.DeliveryMethod = DeliveryMethod.Sequenced;
                    break;

                case PacketProperty.ReliableSequenced:
                    //TODO: netEvent.DeliveryMethod = DeliveryMethod.ReliableSequenced;
                    break;
                }
                netEvent.DataReader.SetSource(packet.CopyPacketData());
                EnqueueEvent(netEvent);
            }
        }
Пример #6
0
        private NetPeer OnConnectionSolved(ConnectionRequest request)
        {
            if (request.Result == ConnectionRequestResult.Reject)
            {
                NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Peer connect reject.");
            }
            else if (GetPeersCount(ConnectionState.Connected | ConnectionState.InProgress) < _maxConnections)
            {
                NetPeer netPeer = null;
                lock (_connectingPeers)
                {
                    if (_connectingPeers.Remove(request.RemoteEndPoint))
                    {
                        //response with id
                        netPeer = new NetPeer(this, request.RemoteEndPoint, request.ConnectionId);
                        NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received peer connection Id: {0}, EP: {1}",
                                            netPeer.ConnectId, netPeer.EndPoint);

                        //add peer to list
                        _peers.Add(request.RemoteEndPoint, netPeer);
                    }
                }
                if (netPeer != null)
                {
                    var netEvent = CreateEvent(NetEventType.Connect);
                    netEvent.Peer = netPeer;
                    EnqueueEvent(netEvent);
                    return(netPeer);
                }

                return(null);
            }
            lock (_connectingPeers)
                _connectingPeers.Remove(request.RemoteEndPoint);
            return(null);
        }
Пример #7
0
        private NetPeer OnConnectionSolved(ConnectionRequest request)
        {
            lock (_connectingPeers)
            {
                if (_connectingPeers.Contains(request.RemoteEndPoint))
                {
                    _connectingPeers.Remove(request.RemoteEndPoint);
                }
                else
                {
                    return(null);
                }
            }
            if (request.Result == ConnectionRequestResult.Reject)
            {
                NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Peer connect reject.");
            }
            else
            {
                //response with id
                var netPeer = new NetPeer(this, request.RemoteEndPoint, request.ConnectionId);
                NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received peer connection Id: {0}, EP: {1}",
                                    netPeer.ConnectId, netPeer.EndPoint);

                lock (_peers)
                {
                    //add peer to list
                    _peers.Add(request.RemoteEndPoint, netPeer);
                }
                var netEvent = CreateEvent(NetEventType.Connect);
                netEvent.Peer = netPeer;
                EnqueueEvent(netEvent);
                return(netPeer);
            }
            return(null);
        }
Пример #8
0
        private void DataReceived(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint)
        {
#if STATS_ENABLED
            PacketsReceived++;
            BytesReceived += (uint)count;
#endif

            //Try read packet
            NetPacket packet = _netPacketPool.GetAndRead(reusableBuffer, 0, count);
            if (packet == null)
            {
                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);
                    EnqueueEvent(netEvent);
                }
                return;

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

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

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

            //Check normal packets
            NetPeer netPeer;

            //Check peers
            Monitor.Enter(_peers);
            int peersCount = _peers.Count;

            if (_peers.TryGetValue(remoteEndPoint, out netPeer))
            {
                Monitor.Exit(_peers);
                //Send
                if (packet.Property == PacketProperty.Disconnect)
                {
                    if (BitConverter.ToInt64(packet.RawData, 1) != netPeer.ConnectId)
                    {
                        //Old or incorrect disconnect
                        _netPacketPool.Recycle(packet);
                        return;
                    }

                    var netEvent = CreateEvent(NetEventType.Disconnect);
                    netEvent.Peer = netPeer;
                    netEvent.DataReader.SetSource(packet.RawData, 5, packet.Size - 5);
                    netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose;
                    EnqueueEvent(netEvent);

                    _peers.Remove(netPeer.EndPoint);
                    //do not recycle because no sense)
                }
                else if (packet.Property == PacketProperty.ConnectAccept)
                {
                    if (netPeer.ProcessConnectAccept(packet))
                    {
                        var connectEvent = CreateEvent(NetEventType.Connect);
                        connectEvent.Peer = netPeer;
                        EnqueueEvent(connectEvent);
                    }
                    _netPacketPool.Recycle(packet);
                }
                else
                {
                    netPeer.ProcessPacket(packet);
                }
                return;
            }

            try
            {
                if (peersCount < _maxConnections && packet.Property == PacketProperty.ConnectRequest)
                {
                    int protoId = BitConverter.ToInt32(packet.RawData, 1);
                    if (protoId != NetConstants.ProtocolId)
                    {
                        NetUtils.DebugWrite(ConsoleColor.Cyan,
                                            "[NM] Peer connect reject. Invalid protocol ID: " + protoId);
                        return;
                    }

                    string peerKey = Encoding.UTF8.GetString(packet.RawData, 13, packet.Size - 13);
                    if (peerKey != _connectKey)
                    {
                        NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Peer connect reject. Invalid key: " + peerKey);
                        return;
                    }

                    //Getting new id for peer
                    long connectionId = BitConverter.ToInt64(packet.RawData, 5);
                    //response with id
                    netPeer = new NetPeer(this, remoteEndPoint, connectionId);
                    NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Received peer connect request Id: {0}, EP: {1}",
                                        netPeer.ConnectId, remoteEndPoint);

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

                    _peers.Add(remoteEndPoint, netPeer);

                    var netEvent = CreateEvent(NetEventType.Connect);
                    netEvent.Peer = netPeer;
                    EnqueueEvent(netEvent);
                }
            }
            finally
            {
                Monitor.Exit(_peers);
            }
        }
        //ProcessAck in packet
        public void ProcessAck(NetPacket packet)
        {
            int validPacketSize = (_windowSize - 1) / BitsInByte + 1 + NetConstants.SequencedHeaderSize;

            if (packet.Size != validPacketSize)
            {
                NetUtils.DebugWrite("[PA]Invalid acks packet size");
                return;
            }

            ushort ackWindowStart = packet.Sequence;

            if (ackWindowStart > NetConstants.MaxSequence)
            {
                NetUtils.DebugWrite("[PA]Bad window start");
                return;
            }

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

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

            Monitor.Enter(_pendingPackets);
            for (int i = 0; i < _windowSize; i++)
            {
                int ackSequence = (ackWindowStart + i) % NetConstants.MaxSequence;
                if (NetUtils.RelativeSequenceNumber(ackSequence, _localWindowStart) < 0)
                {
                    //NetUtils.DebugWrite(ConsoleColor.Cyan, "[PA] SKIP OLD: " + ackSequence);
                    //Skip old ack
                    continue;
                }

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

                if ((acksData[currentByte] & (1 << currentBit)) == 0)
                {
#if STATS_ENABLED || DEBUG
                    if (_pendingPackets[ackSequence % _windowSize].TimeStamp.HasValue)
                    {
                        _peer.Statistics.PacketLoss++;
                    }
#endif
                    //NetUtils.DebugWrite(ConsoleColor.Cyan, "[PA] SKIP FALSE: " + ackSequence);
                    //Skip false ack
                    continue;
                }

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

                PendingPacket pendingPacket = _pendingPackets[ackSequence % _windowSize];
                if (pendingPacket.Packet != null)
                {
                    if (pendingPacket == _headPendingPacket)
                    {
                        _headPendingPacket = _headPendingPacket.Prev;
                    }
                    _peer.Recycle(pendingPacket.Packet);
                    pendingPacket.Clear();
                    NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - true", ackSequence);
                }
                else
                {
                    NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - false", ackSequence);
                }
            }
            Monitor.Exit(_pendingPackets);
        }
Пример #10
0
        internal void Update(int deltaTime)
        {
            _timeSinceLastPacket += deltaTime;
            switch (_connectionState)
            {
            case ConnectionState.Connected:
                if (_timeSinceLastPacket > _netManager.DisconnectTimeout)
                {
                    NetUtils.DebugWrite(
                        "[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, _remoteEndPoint);
                    }
                }
                return;

            case ConnectionState.Outcoming:
                _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, _remoteEndPoint);
                }
                return;

            case ConnectionState.Disconnected:
            case ConnectionState.Incoming:
                return;
            }

            //Send ping
            _pingSendTimer += deltaTime;
            if (_pingSendTimer >= _netManager.PingInterval)
            {
                NetUtils.DebugWrite("[PP] Send ping...");

                //reset timer
                _pingSendTimer = 0;

                //send ping
                _pingPacket.Sequence = _pingSequence;
                _netManager.SendRaw(_pingPacket, _remoteEndPoint);

                //reset timer
                _pingTimeStart = DateTime.UtcNow;
            }

            //RTT - round trip time
            _rttResetTimer += deltaTime;
            if (_rttResetTimer >= RttResetDelay)
            {
                _rttResetTimer = 0;
                //Rtt update
                _rtt  = _avgRtt;
                _ping = _avgRtt;
                _netManager.ConnectionLatencyUpdated(this, _ping);
                _rttCount = 1;
            }

            UpdateMtuLogic(deltaTime);

            //Pending send
            Flush();
        }
Пример #11
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            //not initialized
            if (_connectionState == ConnectionState.Incoming)
            {
                _packetPool.Recycle(packet);
                return;
            }
            if (packet.ConnectionNumber != _connectNum && packet.Property != PacketProperty.ShutdownOk) //without connectionNum
            {
                NetUtils.DebugWrite(ConsoleColor.Red, "[RR]Old packet");
                _packetPool.Recycle(packet);
                return;
            }
            _timeSinceLastPacket = 0;

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

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

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

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

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

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

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

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

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

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

            case PacketProperty.AckReliableSequenced:
                _reliableSequencedChannel.ProcessAck(packet);
                _packetPool.Recycle(packet);
                break;

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

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

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

            default:
                NetUtils.DebugWriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
Пример #12
0
        /// <summary>
        /// Send data to peer
        /// </summary>
        /// <param name="data">Data</param>
        /// <param name="start">Start of data</param>
        /// <param name="length">Length of data</param>
        /// <param name="options">Send options (reliable, unreliable, etc.)</param>
        /// <exception cref="TooBigPacketException">
        ///     If size exceeds maximum limit:<para/>
        ///     MTU - headerSize bytes for Unreliable<para/>
        ///     Fragment count exceeded ushort.MaxValue<para/>
        /// </exception>
        public void Send(byte[] data, int start, int length, DeliveryMethod options)
        {
            if (_connectionState == ConnectionState.ShutdownRequested ||
                _connectionState == ConnectionState.Disconnected)
            {
                return;
            }
            //Prepare
            PacketProperty property = SendOptionsToProperty(options);

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

            //Select channel
            BaseChannel channel;

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

            case PacketProperty.Sequenced:
                channel = _sequencedChannel;
                break;

            case PacketProperty.ReliableOrdered:
                channel = _reliableOrderedChannel;
                break;

            case PacketProperty.Unreliable:
                channel = _unreliableChannel;
                break;

            case PacketProperty.ReliableSequenced:
                channel = _reliableSequencedChannel;
                break;

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

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

            if (length + headerSize > mtu)
            {
                if (options == DeliveryMethod.Sequenced ||
                    options == DeliveryMethod.Unreliable ||
                    options == DeliveryMethod.ReliableSequenced)
                {
                    throw new TooBigPacketException("Unreliable packet size exceeded maximum of " + (_mtu - headerSize) + " bytes");
                }

                int packetFullSize = mtu - headerSize;
                int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize;

                int fullPacketsCount = length / packetDataSize;
                int lastPacketSize   = length % packetDataSize;
                int totalPackets     = fullPacketsCount + (lastPacketSize == 0 ? 0 : 1);

                NetUtils.DebugWrite("FragmentSend:\n" +
                                    " MTU: {0}\n" +
                                    " headerSize: {1}\n" +
                                    " packetFullSize: {2}\n" +
                                    " packetDataSize: {3}\n" +
                                    " fullPacketsCount: {4}\n" +
                                    " lastPacketSize: {5}\n" +
                                    " totalPackets: {6}",
                                    mtu, headerSize, packetFullSize, packetDataSize, fullPacketsCount, lastPacketSize, totalPackets);

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

                int dataOffset = headerSize + NetConstants.FragmentHeaderSize;

                lock (_sendLock)
                {
                    for (ushort i = 0; i < fullPacketsCount; i++)
                    {
                        NetPacket p = _packetPool.GetWithProperty(property, packetFullSize);
                        p.FragmentId     = _fragmentId;
                        p.FragmentPart   = i;
                        p.FragmentsTotal = (ushort)totalPackets;
                        p.MarkFragmented();
                        Buffer.BlockCopy(data, i * packetDataSize, p.RawData, dataOffset, packetDataSize);
                        channel.AddToQueue(p);
                    }
                    if (lastPacketSize > 0)
                    {
                        NetPacket p = _packetPool.GetWithProperty(property, lastPacketSize + NetConstants.FragmentHeaderSize);
                        p.FragmentId     = _fragmentId;
                        p.FragmentPart   = (ushort)fullPacketsCount; //last
                        p.FragmentsTotal = (ushort)totalPackets;
                        p.MarkFragmented();
                        Buffer.BlockCopy(data, fullPacketsCount * packetDataSize, p.RawData, dataOffset, lastPacketSize);
                        channel.AddToQueue(p);
                    }
                    _fragmentId++;
                }
                return;
            }

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

            channel.AddToQueue(packet);
        }
Пример #13
0
        private void DataReceived(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint)
        {
#if STATS_ENABLED
            Statistics.PacketsReceived++;
            Statistics.BytesReceived += (uint)count;
#endif

            //Try read packet
            NetPacket packet = NetPacketPool.GetAndRead(reusableBuffer, 0, count);
            if (packet == null)
            {
                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;
            lock (_peers)
            {
                _peers.TryGetValue(remoteEndPoint, out netPeer);
            }
            if (netPeer != null &&
                netPeer.ConnectionState != ConnectionState.Disconnected)
            {
                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;
                        }

                        var netEvent = CreateEvent(NetEventType.Disconnect);
                        netEvent.Peer = netPeer;
                        netEvent.DataReader.SetSource(packet.RawData, 9, packet.Size);
                        netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose;
                        EnqueueEvent(netEvent);
                    }
                    break;

                case PacketProperty.ShutdownOk:
                    if (netPeer.ConnectionState != ConnectionState.ShutdownRequested)
                    {
                        return;
                    }
                    netPeer.ProcessPacket(packet);
                    NetUtils.DebugWriteForce(ConsoleColor.Cyan, "[NM] ShutdownOK!");
                    break;

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

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

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

            if (packet.Property == PacketProperty.ConnectRequest && packet.Size >= 12)
            {
                int peersCount = GetPeersCount(ConnectionState.Connected | ConnectionState.InProgress);
                lock (_connectingPeers)
                {
                    if (_connectingPeers.Contains(remoteEndPoint))
                    {
                        return;
                    }
                    if (peersCount < _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);
                        }

                        _connectingPeers.Add(remoteEndPoint);
                        var netEvent = CreateEvent(NetEventType.ConnectionRequest);
                        netEvent.ConnectionRequest =
                            new ConnectionRequest(connectionId, remoteEndPoint, reader, OnConnectionSolved);
                        EnqueueEvent(netEvent);
                    }
                }
            }
        }
Пример #14
0
        internal void Update(int deltaTime)
        {
            if (_connectionState == ConnectionState.Connected && _timeSinceLastPacket > _netManager.DisconnectTimeout)
            {
                NetUtils.DebugWrite(
                    "[UPDATE] Disconnect by timeout: {0} > {1}",
                    _timeSinceLastPacket,
                    _netManager.DisconnectTimeout);
                _netManager.DisconnectPeer(this, DisconnectReason.Timeout, 0, true, null, 0, 0);
                return;
            }
            if (_connectionState == ConnectionState.ShutdownRequested)
            {
                if (_timeSinceLastPacket > _netManager.DisconnectTimeout)
                {
                    _connectionState = ConnectionState.Disconnected;
                }
                else
                {
                    _netManager.SendRaw(_shutdownPacket.RawData, 0, _shutdownPacket.Size, _remoteEndPoint);
                }
                return;
            }
            if (_connectionState == ConnectionState.Disconnected)
            {
                return;
            }

            _timeSinceLastPacket += deltaTime;
            if (_connectionState == ConnectionState.InProgress)
            {
                _connectTimer += deltaTime;
                if (_connectTimer > _netManager.ReconnectDelay)
                {
                    _connectTimer = 0;
                    _connectAttempts++;
                    if (_connectAttempts > _netManager.MaxConnectAttempts)
                    {
                        _netManager.DisconnectPeer(this, DisconnectReason.ConnectionFailed, 0, true, null, 0, 0);
                        return;
                    }

                    //else send connect again
                    SendConnectRequest();
                }
                return;
            }

            //Send ping
            _pingSendTimer += deltaTime;
            if (_pingSendTimer >= _netManager.PingInterval)
            {
                NetUtils.DebugWrite("[PP] Send ping...");

                //reset timer
                _pingSendTimer = 0;

                //send ping
                CreateAndSend(PacketProperty.Ping, _pingSequence);

                //reset timer
                _pingTimeStart = DateTime.UtcNow;
            }

            //RTT - round trip time
            _rttResetTimer += deltaTime;
            if (_rttResetTimer >= RttResetDelay)
            {
                _rttResetTimer = 0;
                //Rtt update
                _rtt  = _avgRtt;
                _ping = _avgRtt;
                _netManager.ConnectionLatencyUpdated(this, _ping);
                _rttCount = 1;
            }

            //MTU - Maximum transmission unit
            if (!_finishMtu)
            {
                _mtuCheckTimer += deltaTime;
                if (_mtuCheckTimer >= MtuCheckDelay)
                {
                    _mtuCheckTimer = 0;
                    _mtuCheckAttempts++;
                    if (_mtuCheckAttempts >= MaxMtuCheckAttempts)
                    {
                        _finishMtu = true;
                    }
                    else
                    {
                        lock (_mtuMutex)
                        {
                            //Send increased packet
                            if (_mtuIdx < NetConstants.PossibleMtu.Length - 1)
                            {
                                int newMtu = NetConstants.PossibleMtu[_mtuIdx + 1] - NetConstants.HeaderSize;
                                var p      = _packetPool.Get(PacketProperty.MtuCheck, newMtu);
                                p.RawData[1] = (byte)(_mtuIdx + 1);
                                SendPacket(p);
                            }
                        }
                    }
                }
            }
            //MTU - end
            //Pending send
            Flush();
        }
Пример #15
0
        /// <summary>
        /// Send data to peer
        /// </summary>
        /// <param name="data">Data</param>
        /// <param name="start">Start of data</param>
        /// <param name="length">Length of data</param>
        /// <param name="options">Send options (reliable, unreliable, etc.)</param>
        /// <exception cref="TooBigPacketException">
        ///     If size exceeds maximum limit:<para/>
        ///     MTU - headerSize bytes for Unreliable<para/>
        ///     Fragment count exceeded ushort.MaxValue<para/>
        /// </exception>
        public void Send(byte[] data, int start, int length, DeliveryMethod options)
        {
            if (_connectionState == ConnectionState.ShutdownRequested ||
                _connectionState == ConnectionState.Disconnected)
            {
                return;
            }
            //Prepare
            PacketProperty property   = SendOptionsToProperty(options);
            int            headerSize = NetPacket.GetHeaderSize(property);
            int            mtu        = _mtu;

            //Check fragmentation
            if (length + headerSize > mtu)
            {
                if (options == DeliveryMethod.Sequenced || options == DeliveryMethod.Unreliable)
                {
                    throw new TooBigPacketException("Unreliable packet size exceeded maximum of " + (_mtu - headerSize) + " bytes");
                }

                int packetFullSize = mtu - headerSize;
                int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize;

                int fullPacketsCount = length / packetDataSize;
                int lastPacketSize   = length % packetDataSize;
                int totalPackets     = fullPacketsCount + (lastPacketSize == 0 ? 0 : 1);

                NetUtils.DebugWrite("FragmentSend:\n" +
                                    " MTU: {0}\n" +
                                    " headerSize: {1}\n" +
                                    " packetFullSize: {2}\n" +
                                    " packetDataSize: {3}\n" +
                                    " fullPacketsCount: {4}\n" +
                                    " lastPacketSize: {5}\n" +
                                    " totalPackets: {6}",
                                    mtu, headerSize, packetFullSize, packetDataSize, fullPacketsCount, lastPacketSize, totalPackets);

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

                int dataOffset = headerSize + NetConstants.FragmentHeaderSize;

                lock (_sendLock)
                {
                    for (ushort i = 0; i < fullPacketsCount; i++)
                    {
                        NetPacket p = _packetPool.Get(property, packetFullSize);
                        p.FragmentId     = _fragmentId;
                        p.FragmentPart   = i;
                        p.FragmentsTotal = (ushort)totalPackets;
                        p.IsFragmented   = true;
                        Buffer.BlockCopy(data, i * packetDataSize, p.RawData, dataOffset, packetDataSize);
                        SendPacket(p);
                    }
                    if (lastPacketSize > 0)
                    {
                        NetPacket p = _packetPool.Get(property, lastPacketSize + NetConstants.FragmentHeaderSize);
                        p.FragmentId     = _fragmentId;
                        p.FragmentPart   = (ushort)fullPacketsCount; //last
                        p.FragmentsTotal = (ushort)totalPackets;
                        p.IsFragmented   = true;
                        Buffer.BlockCopy(data, fullPacketsCount * packetDataSize, p.RawData, dataOffset, lastPacketSize);
                        SendPacket(p);
                    }
                    _fragmentId++;
                }
                return;
            }

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

            SendPacket(packet);
        }
Пример #16
0
        //Update function
        private void UpdateLogic()
        {
#if DEBUG
            if (SimulateLatency)
            {
                var time = DateTime.UtcNow;
                lock (_pingSimulationList)
                {
                    for (int i = 0; i < _pingSimulationList.Count; i++)
                    {
                        var incomingData = _pingSimulationList[i];
                        if (incomingData.TimeWhenGet <= time)
                        {
                            DataReceived(incomingData.Data, incomingData.Data.Length, incomingData.EndPoint);
                            _pingSimulationList.RemoveAt(i);
                            i--;
                        }
                    }
                }
            }
#endif

#if STATS_ENABLED
            ulong totalPacketLoss = 0;
#endif
            //Process acks
            lock (_peers)
            {
                int delta = _logicThread.SleepTime;
                for (int i = 0; i < _peers.Count; i++)
                {
                    var netPeer = _peers[i];
                    if (netPeer.ConnectionState == ConnectionState.Connected && netPeer.TimeSinceLastPacket > DisconnectTimeout)
                    {
                        NetUtils.DebugWrite("[NM] Disconnect by timeout: {0} > {1}", netPeer.TimeSinceLastPacket, DisconnectTimeout);
                        var netEvent = CreateEvent(NetEventType.Disconnect);
                        netEvent.Peer             = netPeer;
                        netEvent.DisconnectReason = DisconnectReason.Timeout;
                        EnqueueEvent(netEvent);

                        RemovePeerAt(i);
                        i--;
                    }
                    else if (netPeer.ConnectionState == ConnectionState.Disconnected)
                    {
                        var netEvent = CreateEvent(NetEventType.Disconnect);
                        netEvent.Peer             = netPeer;
                        netEvent.DisconnectReason = DisconnectReason.ConnectionFailed;
                        EnqueueEvent(netEvent);

                        RemovePeerAt(i);
                        i--;
                    }
                    else
                    {
                        netPeer.Update(delta);
#if STATS_ENABLED
                        totalPacketLoss += netPeer.Statistics.PacketLoss;
#endif
                    }
                }
            }
#if STATS_ENABLED
            Statistics.PacketLoss = totalPacketLoss;
#endif
        }