Exemple #1
0
        //Process incoming packet
        public override void ProcessPacket(NetPacket packet)
        {
            int seq = packet.Sequence;

            if (seq >= NetConstants.MaxSequence)
            {
                NetDebug.Write("[RR]Bad sequence");
                return;
            }

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

            if (relateSeq > _windowSize)
            {
                NetDebug.Write("[RR]Bad sequence");
                return;
            }

            //Drop bad packets
            if (relate < 0)
            {
                //Too old packet doesn't ack
                NetDebug.Write("[RR]ReliableInOrder too old");
                return;
            }
            if (relate >= _windowSize * 2)
            {
                //Some very new packet
                NetDebug.Write("[RR]ReliableInOrder too new");
                return;
            }

            //If very new - move window
            int ackIdx;
            int ackByte;
            int ackBit;

            Monitor.Enter(_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.SequencedHeaderSize + 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.SequencedHeaderSize + ackIdx / BitsInByte;
            ackBit        = ackIdx % BitsInByte;
            if ((_outgoingAcks.RawData[ackByte] & (1 << ackBit)) != 0)
            {
                NetDebug.Write("[RR]ReliableInOrder duplicate");
                Monitor.Exit(_outgoingAcks);
                return;
            }

            //save ack
            _outgoingAcks.RawData[ackByte] |= (byte)(1 << ackBit);
            Monitor.Exit(_outgoingAcks);

            //detailed check
            if (seq == _remoteSequence)
            {
                NetDebug.Write("[RR]ReliableInOrder packet succes");
                Peer.AddIncomingPacket(packet);
                _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;

                if (_ordered)
                {
                    NetPacket p;
                    while ((p = _receivedPackets[_remoteSequence % _windowSize]) != null)
                    {
                        //process holded packet
                        _receivedPackets[_remoteSequence % _windowSize] = null;
                        Peer.AddIncomingPacket(p);
                        _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
                    }
                }
                else
                {
                    while (_earlyReceived[_remoteSequence % _windowSize])
                    {
                        //process early packet
                        _earlyReceived[_remoteSequence % _windowSize] = false;
                        _remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
                    }
                }

                return;
            }

            //holded packet
            if (_ordered)
            {
                _receivedPackets[ackIdx] = packet;
            }
            else
            {
                _earlyReceived[ackIdx] = true;
                Peer.AddIncomingPacket(packet);
            }
        }
Exemple #2
0
        private void ReceiveLogic()
        {
            while (_running)
            {
                int errorCode = 0;

                //Receive some info
                byte[] reusableBuffer = null;
                int    result         = _socket.ReceiveFrom(ref reusableBuffer, ref _remoteEndPoint, ref errorCode);

                if (result > 0)
                {
#if DEBUG
                    bool receivePacket = true;

                    if (SimulatePacketLoss && _randomGenerator.Next(100 / SimulationPacketLossChance) == 0)
                    {
                        receivePacket = false;
                    }
                    else if (SimulateLatency)
                    {
                        int latency = _randomGenerator.Next(SimulationMaxLatency);
                        if (latency > 5)
                        {
                            byte[] holdedData = new byte[result];
                            Buffer.BlockCopy(reusableBuffer, 0, holdedData, 0, result);
                            _pingSimulationList.AddFirst(new IncomingData
                            {
                                Data = holdedData, EndPoint = _remoteEndPoint, TimeWhenGet = DateTime.UtcNow.AddMilliseconds(latency)
                            });
                            receivePacket = false;
                        }
                    }

                    if (receivePacket) //DataReceived
#endif
                    //ProcessEvents
                    DataReceived(reusableBuffer, result, _remoteEndPoint);
                }
                else if (result < 0)
                {
                    //10054 - remote close (not error)
                    //10040 - message too long (impossible now)
                    if (errorCode != 10054)
                    {
                        NetUtils.DebugWrite(ConsoleColor.Red, "(NB)Socket error!");
                        ProcessError("Receive socket error: " + errorCode);
                        Stop();
                        return;
                    }
                }
#if DEBUG
                if (SimulateLatency)
                {
                    var node = _pingSimulationList.First;
                    var time = DateTime.UtcNow;
                    while (node != null)
                    {
                        var incomingData = node.Value;
                        if (incomingData.TimeWhenGet <= time)
                        {
                            DataReceived(incomingData.Data, incomingData.Data.Length, incomingData.EndPoint);
                            var nodeToRemove = node;
                            node = node.Next;
                            _pingSimulationList.Remove(nodeToRemove);
                        }
                        else
                        {
                            node = node.Next;
                        }
                    }
                }
#endif
            }
        }
Exemple #3
0
        //ProcessAck in packet
        private void ProcessAck(NetPacket packet)
        {
            if (packet.Size != _outgoingAcks.Size)
            {
                NetDebug.Write("[PA]Invalid acks packet size");
                return;
            }

            var ackWindowStart = packet.Sequence;
            var 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;
            }

            var acksData = packet.RawData;

            lock (_pendingPackets)
            {
                for (var pendingSeq = _localWindowStart;
                     pendingSeq != _localSeqence;
                     pendingSeq = (pendingSeq + 1) % NetConstants.MaxSequence)
                {
                    var rel = NetUtils.RelativeSequenceNumber(pendingSeq, ackWindowStart);
                    if (rel >= _windowSize)
                    {
                        NetDebug.Write("[PA]REL: " + rel);
                        break;
                    }

                    var pendingIdx  = pendingSeq % _windowSize;
                    var currentByte = NetConstants.ChanneledHeaderSize + pendingIdx / BitsInByte;
                    var currentBit  = pendingIdx % BitsInByte;
                    if ((acksData[currentByte] & (1 << currentBit)) == 0)
                    {
#if DEBUG
                        Peer.Statistics.PacketLoss++;
#else
                        if (Peer.NetManager.EnableStatistics)
                        {
                            Peer.Statistics.PacketLoss++;
                        }
#endif

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

#if WIN32 && UNSAFE
            int    saddrSize     = 32;
            byte[] prevAddress   = new byte[saddrSize];
            byte[] socketAddress = new byte[saddrSize];
            byte[] addrBuffer    = new byte[16]; //IPAddress.IPv6AddressBytes
#endif
            byte[] receiveBuffer = new byte[NetConstants.PacketSizeLimit];

            while (_running)
            {
                int result;

                //Reading data
                try
                {
#if WIN32 && UNSAFE
                    result = recvfrom(
                        socket.Handle,
                        receiveBuffer,
                        receiveBuffer.Length,
                        SocketFlags.None,
                        socketAddress,
                        ref saddrSize);
                    if ((SocketError)result == SocketError.SocketError)
                    {
                        throw new SocketException(Marshal.GetLastWin32Error());
                    }

                    bool recreate = false;
                    for (int i = 0; i < saddrSize; i++)
                    {
                        if (socketAddress[i] != prevAddress[i])
                        {
                            prevAddress[i] = socketAddress[i];
                            recreate       = true;
                        }
                    }
                    if (recreate)
                    {
                        if (socket.AddressFamily == AddressFamily.InterNetwork)
                        {
                            int  port    = (socketAddress[2] << 8 & 0xFF00) | socketAddress[3];
                            long address = (
                                (socketAddress[4] & 0x000000FF) |
                                (socketAddress[5] << 8 & 0x0000FF00) |
                                (socketAddress[6] << 16 & 0x00FF0000) |
                                (socketAddress[7] << 24)
                                ) & 0x00000000FFFFFFFF;
                            bufferNetEndPoint = new NetEndPoint(new IPEndPoint(address, port));
                        }
                        else
                        {
                            for (int i = 0; i < addrBuffer.Length; i++)
                            {
                                addrBuffer[i] = socketAddress[i + 8];
                            }
                            int  port  = (socketAddress[2] << 8 & 0xFF00) | (socketAddress[3]);
                            long scope = (socketAddress[27] << 24) +
                                         (socketAddress[26] << 16) +
                                         (socketAddress[25] << 8) +
                                         (socketAddress[24]);
                            bufferNetEndPoint = new NetEndPoint(new IPEndPoint(new IPAddress(addrBuffer, scope), port));
                        }
                    }
#else
                    result = socket.ReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref bufferEndPoint);
                    if (!bufferNetEndPoint.EndPoint.Equals(bufferEndPoint))
                    {
                        bufferNetEndPoint = new NetEndPoint((IPEndPoint)bufferEndPoint);
                    }
#endif
                }
                catch (SocketException ex)
                {
                    if (ex.SocketErrorCode == SocketError.ConnectionReset ||
                        ex.SocketErrorCode == SocketError.MessageSize ||
                        ex.SocketErrorCode == SocketError.Interrupted)
                    {
                        //10040 - message too long
                        //10054 - remote close (not error)
                        //Just UDP
                        NetUtils.DebugWrite(ConsoleColor.DarkRed, "[R] Ingored error: {0} - {1}", (int)ex.SocketErrorCode, ex.ToString());
                        continue;
                    }
                    NetUtils.DebugWriteError("[R]Error code: {0} - {1}", (int)ex.SocketErrorCode, ex.ToString());
                    lock (_receiveLock)
                    {
                        _onMessageReceived(null, 0, (int)ex.SocketErrorCode, bufferNetEndPoint);
                    }

                    continue;
                }

                //All ok!
                NetUtils.DebugWrite(ConsoleColor.Blue, "[R]Received data from {0}, result: {1}", bufferNetEndPoint.ToString(), result);
                lock (_receiveLock)
                {
                    _onMessageReceived(receiveBuffer, result, 0, bufferNetEndPoint);
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Connect to remote host
        /// </summary>
        /// <param name="address">Server IP or hostname</param>
        /// <param name="port">Server Port</param>
        /// <param name="connectionData">Additional data for remote peer</param>
        /// <returns>New NetPeer if new connection, Old NetPeer if already connected</returns>
        /// <exception cref="InvalidOperationException">Manager is not running. Call <see cref="Start()"/></exception>
        public NetPeer Connect(string address, int port, NetDataWriter connectionData)
        {
            var ep = NetUtils.MakeEndPoint(address, port);

            return(Connect(ep, connectionData));
        }
Exemple #6
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;
            }

            //get peer
            //Check normal packets
            NetPeer netPeer;
            //old packets protection
            bool peerFound = _peers.TryGetValue(remoteEndPoint, out netPeer);

            //Check unconnected
            switch (packet.Property)
            {
            case PacketProperty.DiscoveryRequest:
                if (!DiscoveryEnabled)
                {
                    break;
                }
                CreateEvent(NetEvent.EType.DiscoveryRequest, remoteEndPoint: remoteEndPoint, readerSource: packet);
                break;

            case PacketProperty.DiscoveryResponse:
                CreateEvent(NetEvent.EType.DiscoveryResponse, remoteEndPoint: remoteEndPoint, readerSource: packet);
                break;

            case PacketProperty.UnconnectedMessage:
                if (!UnconnectedMessagesEnabled)
                {
                    break;
                }
                CreateEvent(NetEvent.EType.ReceiveUnconnected, remoteEndPoint: remoteEndPoint, readerSource: packet);
                break;

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

            case PacketProperty.Disconnect:
                if (peerFound)
                {
                    var disconnectResult = netPeer.ProcessDisconnect(packet);
                    if (disconnectResult == DisconnectResult.None)
                    {
                        NetPacketPool.Recycle(packet);
                        return;
                    }
                    if (disconnectResult == DisconnectResult.Disconnect)
                    {
                        _connectedPeersCount--;
                    }
                    CreateEvent(
                        NetEvent.EType.Disconnect,
                        netPeer,
                        disconnectReason: disconnectResult == DisconnectResult.Disconnect
                                ? DisconnectReason.RemoteConnectionClose
                                : DisconnectReason.ConnectionRejected,
                        readerSource: packet
                        );
                }
                else
                {
                    NetPacketPool.Recycle(packet);
                }
                //Send shutdown
                SendRaw(new[] { (byte)PacketProperty.ShutdownOk }, 0, 1, remoteEndPoint);
                break;

            case PacketProperty.ConnectAccept:
                var connAccept = NetConnectAcceptPacket.FromData(packet);
                if (connAccept != null && peerFound && netPeer.ProcessConnectAccept(connAccept))
                {
                    CreateEvent(NetEvent.EType.Connect, netPeer);
                }
                break;

            case PacketProperty.ConnectRequest:
                var connRequest = NetConnectRequestPacket.FromData(packet);
                if (connRequest != null)
                {
                    ProcessConnectRequest(remoteEndPoint, netPeer, connRequest);
                }
                break;

            default:
                if (peerFound)
                {
                    netPeer.ProcessPacket(packet);
                }
                break;
            }
        }
Exemple #7
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            _timeSinceLastPacket = 0;
            if (packet.ConnectionNumber != _connectNum &&
                packet.Property != PacketProperty.ShutdownOk) //withou connectionNum
            {
                NetUtils.DebugWrite(ConsoleColor.Red, "[RR]Old packet");
                _packetPool.Recycle(packet);
                return;
            }

            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;
            }
        }
Exemple #8
0
        //Process incoming packet
        internal void ProcessPacket(NetPacket packet)
        {
            //not initialized
            if (_connectionState == ConnectionState.Outgoing || _connectionState == ConnectionState.Disconnected)
            {
                _packetPool.Recycle(packet);
                return;
            }
            if (packet.Property == PacketProperty.ShutdownOk)
            {
                if (_connectionState == ConnectionState.ShutdownRequested)
                {
                    _connectionState = ConnectionState.Disconnected;
                }
                _packetPool.Recycle(packet);
                return;
            }
            if (packet.ConnectionNumber != _connectNum)
            {
                NetDebug.Write(NetLogLevel.Trace, "[RR]Old packet");
                _packetPool.Recycle(packet);
                return;
            }
            Interlocked.Exchange(ref _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;
                    if (packet.RawData.Length - pos < size)
                    {
                        break;
                    }

                    NetPacket mergedPacket = _packetPool.GetPacket(size);
                    Buffer.BlockCopy(packet.RawData, pos, mergedPacket.RawData, 0, size);
                    mergedPacket.Size = size;

                    if (!mergedPacket.Verify())
                    {
                        break;
                    }

                    pos += size;
                    ProcessPacket(mergedPacket);
                }
                _packetPool.Recycle(packet);
                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:
                NetManager.CreateReceiveEvent(packet, DeliveryMethod.Unreliable, NetConstants.HeaderSize, this);
                return;

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

            default:
                NetDebug.WriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
        //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);
            PendingPacket pendingPacket = _headPendingPacket;
            PendingPacket prevPacket    = null;

            while (pendingPacket != null)
            {
                int seq = pendingPacket.Packet.Sequence;
                int rel = NetUtils.RelativeSequenceNumber(seq, ackWindowStart);
                if (rel < 0)
                {
                    prevPacket    = pendingPacket;
                    pendingPacket = pendingPacket.Next;
                    continue;
                }
                if (rel >= _windowSize)
                {
                    break;
                }

                int idx         = (ackWindowStart + seq) % _windowSize;
                int currentByte = startByte + idx / BitsInByte;
                int currentBit  = idx % BitsInByte;
                if ((acksData[currentByte] & (1 << currentBit)) == 0)
                {
#if STATS_ENABLED || DEBUG
                    _peer.Statistics.PacketLoss++;
#endif
                    //Skip false ack
                    prevPacket    = pendingPacket;
                    pendingPacket = pendingPacket.Next;
                    continue;
                }

                if (seq == _localWindowStart)
                {
                    //Move window
                    _headPendingPacket = _headPendingPacket.Next;
                    _localWindowStart  = _headPendingPacket != null
                        ? _headPendingPacket.Packet.Sequence
                        : (_localWindowStart + 1) % NetConstants.MaxSequence;
                }
                if (pendingPacket == _tailPendingPacket)
                {
                    _tailPendingPacket = prevPacket;
                }

                var packetToClear = pendingPacket;

                //move forward
                pendingPacket = pendingPacket.Next;
                if (prevPacket != null)
                {
                    prevPacket.Next = pendingPacket;
                }

                //clear acked packet
                _peer.Recycle(packetToClear.Packet);
                packetToClear.Clear();
                NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - true", seq);
            }
            Monitor.Exit(_pendingPackets);
        }
Exemple #10
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);
        }
        public void SendNextPackets()
        {
            //check sending acks
            if (_mustSendAcks)
            {
                _mustSendAcks = false;
                NetUtils.DebugWrite("[RR]SendAcks");
                Monitor.Enter(_outgoingAcks);
                _peer.SendRawData(_outgoingAcks);
                Monitor.Exit(_outgoingAcks);
            }

            long currentTime = DateTime.UtcNow.Ticks;

            Monitor.Enter(_pendingPackets);
            //get packets from queue
            Monitor.Enter(_outgoingPackets);
            while (_outgoingPackets.Count > 0)
            {
                int relate = NetUtils.RelativeSequenceNumber(_localSeqence, _localWindowStart);
                if (relate < _windowSize)
                {
                    PendingPacket pendingPacket = _pendingPackets[_localSeqence % _windowSize];
                    pendingPacket.Packet          = _outgoingPackets.Dequeue();
                    pendingPacket.Packet.Sequence = (ushort)_localSeqence;
                    if (_headPendingPacket == null)
                    {
                        _headPendingPacket = pendingPacket;
                    }
                    else
                    {
                        _tailPendingPacket.Next = pendingPacket;
                    }
                    _tailPendingPacket = pendingPacket;
                    _localSeqence      = (_localSeqence + 1) % NetConstants.MaxSequence;
                }
                else //Queue filled
                {
                    break;
                }
            }
            Monitor.Exit(_outgoingPackets);

            //if no pending packets return
            if (_headPendingPacket == null)
            {
                Monitor.Exit(_pendingPackets);
                return;
            }
            //send
            double        resendDelay   = _peer.ResendDelay;
            PendingPacket currentPacket = _headPendingPacket;

            do
            {
                if (currentPacket.Sended) //check send time
                {
                    double packetHoldTime = currentTime - currentPacket.TimeStamp;
                    if (packetHoldTime < resendDelay * TimeSpan.TicksPerMillisecond)
                    {
                        continue;
                    }
                    NetUtils.DebugWrite("[RC]Resend: {0} > {1}", (int)packetHoldTime, resendDelay);
                }

                currentPacket.TimeStamp = currentTime;
                currentPacket.Sended    = true;
                _peer.SendRawData(currentPacket.Packet);
            } while ((currentPacket = currentPacket.Next) != null);
            Monitor.Exit(_pendingPackets);
        }
Exemple #12
0
 public void SendNatIntroduceRequest(string host, int port, string additionalInfo)
 {
     SendNatIntroduceRequest(NetUtils.MakeEndPoint(host, port), additionalInfo);
 }
Exemple #13
0
        public int SendTo(byte[] data, int offset, int size, NetEndPoint remoteEndPoint, ref int errorCode)
        {
            try
            {
                var socket = _udpSocketv4;
                if (remoteEndPoint.EndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support)
                {
                    socket = _udpSocketv6;
                }

                int result;
#if WIN32 && UNSAFE
                var      handle            = socket.Handle;
                IntPtr[] fileDescriptorSet = { (IntPtr)1, handle };
                int      socketCount       = select(0, null, fileDescriptorSet, null, ref SendPollTime);
                if ((SocketError)socketCount == SocketError.SocketError)
                {
                    throw new SocketException(Marshal.GetLastWin32Error());
                }
                if ((int)fileDescriptorSet[0] == 0 || fileDescriptorSet[1] != handle)
                {
                    return(0);
                }
                unsafe
                {
                    fixed(byte *pinnedBuffer = data)
                    {
                        result = sendto(
                            handle,
                            pinnedBuffer + offset,
                            size,
                            SocketFlags.None,
                            remoteEndPoint.SocketAddr,
                            remoteEndPoint.SocketAddr.Length);
                    }
                }

                if ((SocketError)result == SocketError.SocketError)
                {
                    throw new SocketException(Marshal.GetLastWin32Error());
                }
#else
                if (!socket.Poll(SocketSendPollTime, SelectMode.SelectWrite))
                {
                    return(-1);
                }
                result = socket.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint.EndPoint);
#endif

                NetUtils.DebugWrite(ConsoleColor.Blue, "[S]Send packet to {0}, result: {1}", remoteEndPoint.EndPoint, result);
                return(result);
            }
            catch (SocketException ex)
            {
                if (ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                {
                    return(0);
                }
                if (ex.SocketErrorCode != SocketError.MessageSize)
                {
                    NetUtils.DebugWriteError("[S]" + ex);
                }

                errorCode = (int)ex.SocketErrorCode;
                return(-1);
            }
            catch (Exception ex)
            {
                NetUtils.DebugWriteError("[S]" + ex);
                return(-1);
            }
        }
Exemple #14
0
        internal void Update(int deltaTime)
        {
            if (_connectionState == ConnectionState.Disconnected)
            {
                return;
            }

            _timeSinceLastPacket += deltaTime;
            if (_connectionState == ConnectionState.InProgress)
            {
                _connectTimer += deltaTime;
                if (_connectTimer > _peerListener.ReconnectDelay)
                {
                    _connectTimer = 0;
                    _connectAttempts++;
                    if (_connectAttempts > _peerListener.MaxConnectAttempts)
                    {
                        _connectionState = ConnectionState.Disconnected;
                        return;
                    }

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

            //Get current flow mode
            int maxSendPacketsCount = _peerListener.GetPacketsPerSecond(_currentFlowMode);
            int currentMaxSend;

            if (maxSendPacketsCount > 0)
            {
                int availableSendPacketsCount = maxSendPacketsCount - _sendedPacketsCount;
                currentMaxSend = Math.Min(availableSendPacketsCount, (maxSendPacketsCount * deltaTime) / NetConstants.FlowUpdateTime);
            }
            else
            {
                currentMaxSend = int.MaxValue;
            }

            //DebugWrite("[UPDATE]Delta: {0}ms, MaxSend: {1}", deltaTime, currentMaxSend);

            //Pending acks
            _reliableOrderedChannel.SendAcks();
            _reliableUnorderedChannel.SendAcks();

            //ResetFlowTimer
            _flowTimer += deltaTime;
            if (_flowTimer >= NetConstants.FlowUpdateTime)
            {
                NetUtils.DebugWrite("[UPDATE]Reset flow timer, _sendedPackets - {0}", _sendedPacketsCount);
                _sendedPacketsCount = 0;
                _flowTimer          = 0;
            }

            //Send ping
            _pingSendTimer += deltaTime;
            if (_pingSendTimer >= _peerListener.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;
                _peerListener.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
            lock (_flushLock)
            {
                SendQueuedPackets(currentMaxSend);
            }
        }
Exemple #15
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.DisconnectPeer(this, DisconnectReason.Timeout, 0, true, null, 0, 0);
                    return;
                }
                break;

            case ConnectionState.ShutdownRequested:
                if (_timeSinceLastPacket > _netManager.DisconnectTimeout)
                {
                    _connectionState = ConnectionState.Disconnected;
                }
                else
                {
                    _netManager.SendRaw(_shutdownPacket, _remoteEndPoint);
                }
                return;

            case 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
                    _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;
                SendRawData(_pingPacket);

                //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.GetWithProperty(PacketProperty.MtuCheck, newMtu);
                                p.RawData[1] = (byte)(_mtuIdx + 1);

                                //Must check result for MTU fix
                                if (!_netManager.SendRawAndRecycle(p, _remoteEndPoint))
                                {
                                    _finishMtu = true;
                                }
                            }
                        }
                    }
                }
            }
            //MTU - end
            //Pending send
            Flush();
        }
Exemple #16
0
        public bool Bind(int port)
        {
            _udpSocketv4                   = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _udpSocketv4.Blocking          = false;
            _udpSocketv4.ReceiveBufferSize = NetConstants.SocketBufferSize;
            _udpSocketv4.SendBufferSize    = NetConstants.SocketBufferSize;
            _udpSocketv4.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, NetConstants.SocketTTL);
#if !NETCORE
            _udpSocketv4.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
#endif

            try
            {
                _udpSocketv4.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
            }
            catch (SocketException e)
            {
                NetUtils.DebugWriteError("Broadcast error: {0}", e.ToString());
            }

            if (!BindSocket(_udpSocketv4, new IPEndPoint(IPAddress.Any, port)))
            {
                return(false);
            }
            _localEndPoint = new NetEndPoint((IPEndPoint)_udpSocketv4.LocalEndPoint);

            _running               = true;
            _threadv4              = new Thread(ReceiveLogic);
            _threadv4.Name         = "SocketThreadv4(" + port + ")";
            _threadv4.IsBackground = true;
            _threadv4.Start(_udpSocketv4);

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

            //Use one port for two sockets
            port = _localEndPoint.Port;

            _udpSocketv6                   = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
            _udpSocketv6.Blocking          = false;
            _udpSocketv6.ReceiveBufferSize = NetConstants.SocketBufferSize;
            _udpSocketv6.SendBufferSize    = NetConstants.SocketBufferSize;

            if (BindSocket(_udpSocketv6, new IPEndPoint(IPAddress.IPv6Any, port)))
            {
                _localEndPoint = new NetEndPoint((IPEndPoint)_udpSocketv6.LocalEndPoint);

                try
                {
                    _udpSocketv6.SetSocketOption(
                        SocketOptionLevel.IPv6,
                        SocketOptionName.AddMembership,
                        new IPv6MulticastOption(MulticastAddressV6));
                }
                catch
                {
                    // Unity3d throws exception - ignored
                }

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

            return(true);
        }
Exemple #17
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);
        }
Exemple #18
0
        /// <summary>
        /// Connect to remote host
        /// </summary>
        /// <param name="address">Server IP or hostname</param>
        /// <param name="port">Server Port</param>
        /// <param name="key">Connection key</param>
        /// <returns>New NetPeer if new connection, Old NetPeer if already connected</returns>
        /// <exception cref="InvalidOperationException">Manager is not running. Call <see cref="Start()"/></exception>
        public NetPeer Connect(string address, int port, string key)
        {
            var ep = NetUtils.MakeEndPoint(address, port);

            return(Connect(ep, key));
        }
Exemple #19
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;
            }

            //Pending send
            Flush();
        }
Exemple #20
0
        private void ProcessConnectRequest(
            IPEndPoint remoteEndPoint,
            NetPeer netPeer,
            NetConnectRequestPacket connRequest)
        {
            byte connectionNumber = connRequest.ConnectionNumber;

            //if we have peer
            if (netPeer != null)
            {
                NetUtils.DebugWrite("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", netPeer.ConnectId, connRequest.ConnectionId, remoteEndPoint);
                var processResult = netPeer.ProcessConnectRequest(connRequest);
                switch (processResult)
                {
                case ConnectRequestResult.Reconnection:
                    _connectedPeersCount--;
                    CreateEvent(NetEvent.EType.Disconnect, netPeer, disconnectReason: DisconnectReason.RemoteConnectionClose);
                    _peers.RemovePeer(netPeer);
                    //go to new connection
                    break;

                case ConnectRequestResult.NewConnection:
                    _peers.RemovePeer(netPeer);
                    //go to new connection
                    break;

                case ConnectRequestResult.P2PConnection:
                    CreateEvent(
                        NetEvent.EType.ConnectionRequest,
                        connectionRequest: new ConnectionRequest(
                            netPeer.ConnectId,
                            connectionNumber,
                            ConnectionRequestType.PeerToPeer,
                            connRequest.Data,
                            netPeer,
                            this)
                        );
                    return;

                default:
                    //no operations needed
                    return;
                }
                //ConnectRequestResult.NewConnection
                //Set next connection number
                connectionNumber = (byte)((netPeer.ConnectionNum + 1) % NetConstants.MaxConnectionNumber);
                //To reconnect peer
            }
            else
            {
                NetUtils.DebugWrite("ConnectRequest Id: {0}, EP: {1}", connRequest.ConnectionId, remoteEndPoint);
            }
            //Add new peer and craete ConnectRequest event
            NetUtils.DebugWrite("[NM] Creating request event: " + connRequest.ConnectionId);
            netPeer = new NetPeer(this, remoteEndPoint);
            if (_peers.TryAdd(netPeer) == netPeer)
            {
                CreateEvent(NetEvent.EType.ConnectionRequest, connectionRequest: new ConnectionRequest(
                                connRequest.ConnectionId,
                                connectionNumber,
                                ConnectionRequestType.Incoming,
                                connRequest.Data,
                                netPeer,
                                this));
            }
        }
Exemple #21
0
        protected override void ReceiveFromSocket(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint)
        {
            NetPacket packet;
            NetPeer   netPeer;

            //Check peers
            if (_peers.TryGetValue(remoteEndPoint, out netPeer))
            {
                packet = netPeer.GetPacketFromPool(init: false);

                //Bad packet check
                if (!packet.FromBytes(reusableBuffer, count))
                {
                    netPeer.Recycle(packet);
                    return;
                }

                //Send
                if (packet.Property == PacketProperty.Disconnect)
                {
                    if (BitConverter.ToUInt64(packet.RawData, 1) != _peerConnectionIds[remoteEndPoint])
                    {
                        //Old or incorrect disconnect
                        netPeer.Recycle(packet);
                        return;
                    }
                    RemovePeer(netPeer);
                    var netEvent = CreateEvent(NetEventType.Disconnect);
                    netEvent.Peer           = netPeer;
                    netEvent.AdditionalInfo = "successfuly disconnected";
                    EnqueueEvent(netEvent);
                }
                else if (packet.Property == PacketProperty.ConnectRequest) //response with connect
                {
                    ulong lastId = _peerConnectionIds[remoteEndPoint];
                    ulong newId  = BitConverter.ToUInt64(packet.RawData, 1);
                    if (newId > lastId)
                    {
                        _peerConnectionIds[remoteEndPoint] = newId;
                    }

                    NetUtils.DebugWrite(ConsoleColor.Cyan, "ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", lastId, newId, remoteEndPoint);
                    SendConnectAccept(netPeer, _peerConnectionIds[remoteEndPoint]);
                    netPeer.Recycle(packet);
                }
                else //throw out garbage packets
                {
                    netPeer.ProcessPacket(packet);
                }
                return;
            }

            //Else add new peer
            packet = new NetPacket();
            if (!packet.FromBytes(reusableBuffer, count))
            {
                //Bad packet
                return;
            }

            if (_peers.Count < _maxClients && packet.Property == PacketProperty.ConnectRequest)
            {
                string peerKey = Encoding.UTF8.GetString(packet.RawData, 9, packet.RawData.Length - 9);
                if (peerKey != _connectKey)
                {
                    NetUtils.DebugWrite(ConsoleColor.Cyan, "[NS] Peer connect reject. Invalid key: " + peerKey);
                    return;
                }

                //Getting new id for peer
                netPeer = CreatePeer(remoteEndPoint);

                //response with id
                ulong connectionId = BitConverter.ToUInt64(packet.RawData, 1);
                NetUtils.DebugWrite(ConsoleColor.Cyan, "[NS] Received peer connect request Id: {0}, EP: {1}", connectionId, remoteEndPoint);


                SendConnectAccept(netPeer, connectionId);

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

                lock (_peers)
                {
                    _peers.Add(remoteEndPoint, netPeer);
                    _peerConnectionIds.Add(remoteEndPoint, connectionId);
                }

                var netEvent = CreateEvent(NetEventType.Connect);
                netEvent.Peer = netPeer;
                EnqueueEvent(netEvent);
            }
        }
Exemple #22
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
            {
                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, _remoteEndPoint);
                }
                _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;

            //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:
                NetDebug.WriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
Exemple #23
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>
        public void Send(byte[] data, int start, int length, SendOptions options)
        {
            //Prepare
            PacketProperty property   = SendOptionsToProperty(options);
            int            headerSize = NetPacket.GetHeaderSize(property);

            //Check fragmentation
            if (length + headerSize > _mtu)
            {
                if (options == SendOptions.Sequenced || options == SendOptions.Unreliable)
                {
                    throw new Exception("Unreliable packet size > allowed (" + (_mtu - headerSize) + ")");
                }

                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 Exception("Too many fragments: " + totalPackets + " > " + ushort.MaxValue);
                }

                int dataOffset = headerSize + NetConstants.FragmentHeaderSize;
                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);
        }
Exemple #24
0
        public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool reuseAddress)
        {
            _udpSocketv4                   = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _udpSocketv4.Blocking          = true;
            _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          = true;
            _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 #25
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.Get(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
                _peerListener.ReceiveFromPeer(resultingPacket, _remoteEndPoint);

                //Clear memory
                _packetPool.Recycle(resultingPacket);
                _holdedFragments.Remove(packetFragId);
            }
            else //Just simple packet
            {
                _peerListener.ReceiveFromPeer(p, _remoteEndPoint);
                _packetPool.Recycle(p);
            }
        }
Exemple #26
0
        public override void SendNextPackets()
        {
            //check sending acks
            if (_mustSendAcks)
            {
                _mustSendAcks = false;
                NetDebug.Write("[RR]SendAcks");
                Monitor.Enter(_outgoingAcks);
                Peer.SendUserData(_outgoingAcks);
                Monitor.Exit(_outgoingAcks);
            }

            long currentTime = DateTime.UtcNow.Ticks;

            Monitor.Enter(_pendingPackets);
            //get packets from queue
            Monitor.Enter(OutgoingQueue);
            while (OutgoingQueue.Count > 0)
            {
                int relate = NetUtils.RelativeSequenceNumber(_localSeqence, _localWindowStart);
                if (relate < _windowSize)
                {
                    PendingPacket pendingPacket = _pendingPackets[_localSeqence % _windowSize];
                    pendingPacket.Sended          = false;
                    pendingPacket.Packet          = OutgoingQueue.Dequeue();
                    pendingPacket.Packet.Sequence = (ushort)_localSeqence;
                    _localSeqence = (_localSeqence + 1) % NetConstants.MaxSequence;
                }
                else //Queue filled
                {
                    break;
                }
            }
            Monitor.Exit(OutgoingQueue);
            //send
            double resendDelay = Peer.ResendDelay;

            for (int pendingSeq = _localWindowStart; pendingSeq != _localSeqence; pendingSeq = (pendingSeq + 1) % NetConstants.MaxSequence)
            {
                PendingPacket currentPacket = _pendingPackets[pendingSeq % _windowSize];
                if (currentPacket.Packet == null)
                {
                    continue;
                }

                if (currentPacket.Sended) //check send time
                {
                    double packetHoldTime = currentTime - currentPacket.TimeStamp;
                    if (packetHoldTime < resendDelay * TimeSpan.TicksPerMillisecond)
                    {
                        continue;
                    }
                    NetDebug.Write("[RC]Resend: {0} > {1}", (int)packetHoldTime, resendDelay);
                }

                currentPacket.TimeStamp = currentTime;
                currentPacket.Sended    = true;
                Peer.SendUserData(currentPacket.Packet);
            }
            Monitor.Exit(_pendingPackets);
        }
Exemple #27
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
                long newId = BitConverter.ToInt64(packet.RawData, NetConstants.RequestConnectIdIndex);
                if (newId > _connectId)
                {
                    _connectId = newId;
                }

                NetUtils.DebugWrite("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", ConnectId, newId, _remoteEndPoint);
                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.GetAndRead(packet.RawData, pos, size);
                    if (mergedPacket == null)
                    {
                        _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
                CreateAndSend(PacketProperty.Pong, _remotePingSequence);
                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.Reliable:
                _reliableUnorderedChannel.ProcessPacket(packet);
                break;

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

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

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

            default:
                NetUtils.DebugWriteError("Error! Unexpected packet type: " + packet.Property);
                break;
            }
        }
Exemple #28
0
        //ProcessAck in packet
        public 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;
            Monitor.Enter(_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.SequencedHeaderSize + pendingIdx / BitsInByte;
                int currentBit  = pendingIdx % BitsInByte;
                if ((acksData[currentByte] & (1 << currentBit)) == 0)
                {
#if STATS_ENABLED || DEBUG
                    Peer.Statistics.PacketLoss++;
#endif
                    //Skip false ack
                    NetDebug.Write("[PA]False ack: {0}", pendingSeq);
                    continue;
                }
                if (pendingSeq == _localWindowStart)
                {
                    //Move window
                    _localWindowStart = (_localWindowStart + 1) % NetConstants.MaxSequence;
                }

                //clear packet
                var pendingPacket = _pendingPackets[pendingIdx];
                if (pendingPacket.Packet != null)
                {
                    Peer.Recycle(pendingPacket.Packet);
                    pendingPacket.Packet = null;
                    NetDebug.Write("[PA]Removing reliableInOrder ack: {0} - true", pendingSeq);
                }
            }
            Monitor.Exit(_pendingPackets);
        }
Exemple #29
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);
                    }
                }
            }
        }