Exemple #1
0
        private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage, Player player)
        {
            int spId    = package._splitPacketId;
            int spIdx   = package._splitPacketIndex;
            int spCount = package._splitPacketCount;

            if (!playerSession.Splits.ContainsKey(spId))
            {
                playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]);
            }

            SplitPartPackage[] spPackets = playerSession.Splits[spId];
            spPackets[spIdx] = splitMessage;

            bool haveEmpty = false;

            for (int i = 0; i < spPackets.Length; i++)
            {
                haveEmpty = haveEmpty || spPackets[i] == null;
            }

            if (!haveEmpty)
            {
                Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

                SplitPartPackage[] waste;
                playerSession.Splits.TryRemove(spId, out waste);

                MemoryStream stream = new MemoryStream();
                for (int i = 0; i < spPackets.Length; i++)
                {
                    SplitPartPackage splitPartPackage = spPackets[i];
                    byte[]           buf = splitPartPackage.Message;
                    if (buf == null)
                    {
                        Log.Error("Expected bytes in splitpart, but got none");
                        continue;
                    }

                    stream.Write(buf, 0, buf.Length);
                    splitPartPackage.PutPool();
                }

                byte[] buffer = stream.ToArray();
                try
                {
                    Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                    fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
                    fullMessage.ReliableMessageNumber  = package._reliableMessageNumber;
                    fullMessage.OrderingChannel        = package._orderingChannel;
                    fullMessage.OrderingIndex          = package._orderingIndex;
                    HandlePackage(fullMessage, playerSession);
                    fullMessage.PutPool();
                }
                catch (Exception e)
                {
                    player.Disconnect("Bad package received from client.");
                }
            }
        }
Exemple #2
0
        private void HandleRakNetMessage(IPEndPoint senderEndpoint, OpenConnectionRequest2 incoming)
        {
            PlayerNetworkSession session;

            lock (_playerSessions)
            {
                DateTime trash;
                if (!_connectionAttemps.TryRemove(senderEndpoint, out trash))
                {
                    Log.WarnFormat("Unexpected connection request packet from {0}. Probably a resend.", senderEndpoint.Address);
                    return;
                }

                if (_playerSessions.TryGetValue(senderEndpoint, out session))
                {
                    // Already connecting, then this is just a duplicate
                    if (session.State == ConnectionState.Connecting /* && DateTime.UtcNow < session.LastUpdatedTime + TimeSpan.FromSeconds(2)*/)
                    {
                        return;
                    }

                    Log.InfoFormat("Unexpected session from {0}. Removing old session and disconnecting old player.", senderEndpoint.Address);

                    Player oldPlayer = session.Player;
                    oldPlayer?.Disconnect("Reconnecting.", false);

                    _playerSessions.TryRemove(senderEndpoint, out session);
                }

                session = new PlayerNetworkSession(null, senderEndpoint, incoming.mtuSize)
                {
                    State           = ConnectionState.Connecting,
                    LastUpdatedTime = DateTime.UtcNow,
                    Mtuize          = incoming.mtuSize
                };

                _playerSessions.TryAdd(senderEndpoint, session);
            }

            Player player = PlayerFactory.CreatePlayer(this, senderEndpoint);

            player.ClientGuid     = incoming.clientGuid;
            player.NetworkSession = session;
            session.Player        = player;

            var reply = OpenConnectionReply2.CreateObject();

            reply.serverGuid             = 12345;
            reply.clientendpoint         = senderEndpoint;
            reply.mtuSize                = incoming.mtuSize;
            reply.doSecurityAndHandshake = new byte[1];
            var data = reply.Encode();

            reply.PutPool();

            TraceSend(reply);

            SendData(data, senderEndpoint);
        }
Exemple #3
0
		private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage, Player player)
		{
			int spId = package._splitPacketId;
			int spIdx = package._splitPacketIndex;
			int spCount = package._splitPacketCount;

			if (!playerSession.Splits.ContainsKey(spId))
			{
				playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]);
			}

			SplitPartPackage[] spPackets = playerSession.Splits[spId];
			spPackets[spIdx] = splitMessage;

			bool haveEmpty = false;
			for (int i = 0; i < spPackets.Length; i++)
			{
				haveEmpty = haveEmpty || spPackets[i] == null;
			}

			if (!haveEmpty)
			{
				Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

				SplitPartPackage[] waste;
				playerSession.Splits.TryRemove(spId, out waste);

				MemoryStream stream = new MemoryStream();
				for (int i = 0; i < spPackets.Length; i++)
				{
					SplitPartPackage splitPartPackage = spPackets[i];
					byte[] buf = splitPartPackage.Message;
					if (buf == null)
					{
						Log.Error("Expected bytes in splitpart, but got none");
						continue;
					}

					stream.Write(buf, 0, buf.Length);
					splitPartPackage.PutPool();
				}

				byte[] buffer = stream.ToArray();
				try
				{
					Package fullMessage = PackageFactory.CreatePackage(buffer[1], buffer) ?? new UnknownPackage(buffer[1], buffer);
					Log.Debug($"0x{fullMessage.Id:x2}\n{Package.HexDump(buffer)}");

					fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
					fullMessage.ReliableMessageNumber = package._reliableMessageNumber;
					fullMessage.OrderingChannel = package._orderingChannel;
					fullMessage.OrderingIndex = package._orderingIndex;
					HandlePackage(fullMessage, playerSession);
					fullMessage.PutPool();
				}
				catch (Exception e)
				{
					player.Disconnect("Bad package received from client.");
				}
			}
		}
Exemple #4
0
 public void Kick(Player player, string otherUser)
 {
     player.Level.BroadcastMessage(string.Format(ChatColors.Gold + "{0} tried to kick {1} but kicked self instead!!", player.Username, otherUser), type: MessageType.Raw);
     player.Disconnect("You kicked yourself :-)");
 }
Exemple #5
0
 public void Ban(Player player, string otherUser)
 {
     player.Level.BroadcastMessage(string.Format(ChatColors.Gold + "{0} tried to ban {1} but banned self instead!!", player.Username, otherUser), type: MessageType.Raw);
     player.Disconnect("Oopps, banned the wrong player. See ya soon!!");
 }
Exemple #6
0
        private void ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint)
        {
            byte msgId = receiveBytes[0];

            if (msgId == 0xFE)
            {
                Log.InfoFormat("A query detected from: {0}", senderEndpoint.Address);
                HandleQuery(receiveBytes, senderEndpoint);
            }
            else if (msgId <= (byte)DefaultMessageIdTypes.ID_USER_PACKET_ENUM)
            {
                HandleRakNetMessage(receiveBytes, senderEndpoint, msgId);
            }
            else
            {
                PlayerNetworkSession playerSession;
                if (!_playerSessions.TryGetValue(senderEndpoint, out playerSession))
                {
                    //Log.DebugFormat("Receive MCPE message 0x{1:x2} without session {0}", senderEndpoint.Address, msgId);
                    //if (!_badPacketBans.ContainsKey(senderEndpoint.Address))
                    //{
                    //	_badPacketBans.Add(senderEndpoint.Address, true);
                    //}
                    return;
                }

                Player player = playerSession.Player;

                if (player == null)
                {
                    Log.ErrorFormat("Receive MCPE message 0x{1:x2} without player {0}. Session removed.", senderEndpoint.Address, msgId);
                    _playerSessions.TryRemove(senderEndpoint, out playerSession);
                    //if (!_badPacketBans.ContainsKey(senderEndpoint.Address))
                    //{
                    //	_badPacketBans.Add(senderEndpoint.Address, true);
                    //}
                    return;
                }

                if (playerSession.Evicted)
                {
                    return;
                }

                playerSession.LastUpdatedTime = DateTime.UtcNow;

                DatagramHeader header = new DatagramHeader(receiveBytes[0]);
                if (!header.isACK && !header.isNAK && header.isValid)
                {
                    if (receiveBytes[0] == 0xa0)
                    {
                        throw new Exception("Receive ERROR, NAK in wrong place");
                    }

                    ConnectedPackage package = ConnectedPackage.CreateObject();
                    try
                    {
                        package.Decode(receiveBytes);
                    }
                    catch (Exception e)
                    {
                        player.Disconnect("Bad package received from client.");
                        //if (Log.IsDebugEnabled)
                        {
                            Log.Warn("Bad packet " + receiveBytes[0], e);
                        }

                        GreylistManager.Blacklist(senderEndpoint.Address);

                        return;
                    }


                    // IF reliable code below is enabled, useItem start sending doubles
                    // for some unknown reason.

                    //Reliability reliability = package._reliability;
                    //if (reliability == Reliability.Reliable
                    //	|| reliability == Reliability.ReliableSequenced
                    //	|| reliability == Reliability.ReliableOrdered
                    //	)
                    {
                        EnqueueAck(playerSession, package._datagramSequenceNumber);
                    }


                    DelayedProcessing(playerSession, package);
                    package.PutPool();
                }
                else if (header.isACK && header.isValid)
                {
                    HandleAck(playerSession, receiveBytes);
                }
                else if (header.isNAK && header.isValid)
                {
                    HandleNak(playerSession, receiveBytes);
                }
                else if (!header.isValid)
                {
                    Log.Warn("!!!! ERROR, Invalid header !!!!!");
                }
            }
        }
Exemple #7
0
        private void Update(object state)
        {
            if (!Monitor.TryEnter(_updateGlobalLock))
            {
                return;
            }
            _forceQuitTimer.Restart();

            try
            {
                long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                Parallel.ForEach(_playerSessions, delegate(KeyValuePair <IPEndPoint, PlayerNetworkSession> pair)
                {
                    PlayerNetworkSession session = pair.Value;

                    if (session == null)
                    {
                        return;
                    }
                    if (session.Evicted)
                    {
                        return;
                    }

                    Player player = session.Player;

                    long lastUpdate     = session.LastUpdatedTime.Ticks / TimeSpan.TicksPerMillisecond;
                    bool serverHasNoLag = ServerInfo.AvailableBytes < 1000;

                    if (serverHasNoLag && lastUpdate + InacvitityTimeout + 3000 < now)
                    {
                        session.Evicted = true;
                        // Disconnect user
                        ThreadPool.QueueUserWorkItem(delegate(object o)
                        {
                            PlayerNetworkSession s = o as PlayerNetworkSession;
                            if (s != null)
                            {
                                Player p = s.Player;
                                if (p != null)
                                {
                                    p.Disconnect("You've been kicked with reason: Network timeout.");
                                }
                                else
                                {
                                    if (ServerInfo.PlayerSessions.TryRemove(session.EndPoint, out session))
                                    {
                                        session.Player  = null;
                                        session.State   = ConnectionState.Unconnected;
                                        session.Evicted = true;
                                        session.Clean();
                                    }
                                }
                            }
                        }, session);

                        return;
                    }


                    if (serverHasNoLag && session.State != ConnectionState.Connected && player != null && lastUpdate + 3000 < now)
                    {
                        ThreadPool.QueueUserWorkItem(delegate(object o)
                        {
                            PlayerNetworkSession s = o as PlayerNetworkSession;
                            if (s != null)
                            {
                                Player p = s.Player;
                                if (p != null)
                                {
                                    p.Disconnect("You've been kicked with reason: Lost connection.");
                                }
                            }
                        }, session);

                        return;
                    }

                    if (player == null)
                    {
                        return;
                    }

                    if (serverHasNoLag && lastUpdate + InacvitityTimeout < now && !session.WaitForAck)
                    {
                        player.DetectLostConnection();
                        session.WaitForAck = true;
                    }

                    if (player.Rto == 0)
                    {
                        return;
                    }

                    long rto  = Math.Max(100, player.Rto);
                    var queue = session.WaitingForAcksQueue;

                    foreach (KeyValuePair <int, Datagram> datagramPair in queue)
                    {
                        // We don't do too much processing in each step, becasue one bad queue will hold the others.
                        //if (_forceQuitTimer.ElapsedMilliseconds > 100)
                        //{
                        //	Log.WarnFormat("Update aborted early");
                        //	return;
                        //}

                        var datagram = datagramPair.Value;

                        if (!datagram.Timer.IsRunning)
                        {
                            Log.ErrorFormat("Timer not running for #{0}", datagram.Header.datagramSequenceNumber);
                            datagram.Timer.Restart();
                            continue;
                        }

                        if (player.Rtt == -1)
                        {
                            return;
                        }

                        //if (session.WaitForAck) return;

                        long elapsedTime    = datagram.Timer.ElapsedMilliseconds;
                        long datagramTimout = rto * (datagram.TransmissionCount + session.ResendCount + 1);
                        datagramTimout      = Math.Min(datagramTimout, 3000);

                        //if(elapsedTime > 5000)
                        //{
                        //	Datagram deleted;
                        //	queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted);
                        //}
                        //else
                        if (serverHasNoLag && elapsedTime >= datagramTimout)
                        {
                            //if (session.WaitForAck) return;

                            //session.WaitForAck = session.ResendCount++ > 3;

                            Datagram deleted;
                            if (queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted))
                            {
                                session.ErrorCount++;

                                if (deleted.TransmissionCount > 3)
                                {
                                    if (Log.IsDebugEnabled)
                                    {
                                        Log.WarnFormat("TIMEOUT, Retransmission count remove from ACK queue #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTO {5}",
                                                       deleted.Header.datagramSequenceNumber.IntValue(),
                                                       player.Username,
                                                       deleted.FirstMessageId,
                                                       elapsedTime,
                                                       datagramTimout,
                                                       rto);
                                    }

                                    deleted.PutPool();

                                    //session.WaitForAck = true;

                                    Interlocked.Increment(ref ServerInfo.NumberOfFails);

                                    continue;
                                }

                                if (!session.Evicted)
                                {
                                    ThreadPool.QueueUserWorkItem(delegate(object data)
                                    {
                                        if (Log.IsDebugEnabled)
                                        {
                                            Log.WarnFormat("TIMEOUT, Resent #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTO {5}",
                                                           deleted.Header.datagramSequenceNumber.IntValue(),
                                                           player.Username,
                                                           deleted.FirstMessageId,
                                                           elapsedTime,
                                                           datagramTimout,
                                                           player.Rto);
                                        }
                                        SendDatagram(session, (Datagram)data);
                                        Interlocked.Increment(ref ServerInfo.NumberOfResends);
                                    }, datagram);
                                }
                            }
                        }
                    }
                });
            }
            finally
            {
                if (_forceQuitTimer.ElapsedMilliseconds > 100)
                {
                    Log.WarnFormat("Update took unexpected long time: {0}", _forceQuitTimer.ElapsedMilliseconds);
                }

                Monitor.Exit(_updateGlobalLock);
                _cleanerTimer.Change(10, Timeout.Infinite);
            }
        }
Exemple #8
0
        private void DelayedProcessing(PlayerNetworkSession playerSession, ConnectedPackage package)
        {
            Player player = playerSession.Player;

            if (ForwardAllPlayers)
            {
                player.SendPackage(new McpeTransfer
                {
                    endpoint = ForwardTarget
                }, true);

                return;
            }

            List <Package> messages = package.Messages;

            foreach (var message in messages)
            {
                message.DatagramSequenceNumber = package._datagramSequenceNumber;
                message.OrderingChannel        = package._orderingChannel;
                message.OrderingIndex          = package._orderingIndex;

                if (message is SplitPartPackage)
                {
                    message.Source = "Receive SplitPartPackage";

                    SplitPartPackage splitMessage = message as SplitPartPackage;

                    int spId    = package._splitPacketId;
                    int spIdx   = package._splitPacketIndex;
                    int spCount = package._splitPacketCount;

                    if (!playerSession.Splits.ContainsKey(spId))
                    {
                        playerSession.Splits.Add(spId, new SplitPartPackage[spCount]);
                    }

                    SplitPartPackage[] spPackets = playerSession.Splits[spId];
                    spPackets[spIdx] = splitMessage;

                    bool haveEmpty = false;
                    for (int i = 0; i < spPackets.Length; i++)
                    {
                        haveEmpty = haveEmpty || spPackets[i] == null;
                    }

                    if (!haveEmpty)
                    {
                        Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

                        MemoryStream stream = new MemoryStream();
                        for (int i = 0; i < spPackets.Length; i++)
                        {
                            SplitPartPackage splitPartPackage = spPackets[i];
                            byte[]           buf = splitPartPackage.Message;
                            stream.Write(buf, 0, buf.Length);
                            splitPartPackage.PutPool();
                        }

                        playerSession.Splits.Remove(spId);

                        byte[] buffer = stream.ToArray();
                        try
                        {
                            Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                            fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
                            fullMessage.OrderingChannel        = package._orderingChannel;
                            fullMessage.OrderingIndex          = package._orderingIndex;
                            HandlePackage(fullMessage, playerSession);
                            fullMessage.PutPool();
                        }
                        catch (Exception e)
                        {
                            player.Disconnect("Bad package received from client.");
                        }
                    }

                    continue;
                }

                message.Timer.Restart();
                HandlePackage(message, playerSession);
                message.PutPool();                 // Handled in HandlePacket now()
            }
        }
Exemple #9
0
        private void HandleRakNetMessage(byte[] receiveBytes, IPEndPoint senderEndpoint, byte msgId)
        {
            DefaultMessageIdTypes msgIdType = (DefaultMessageIdTypes)msgId;

            Package message = PackageFactory.CreatePackage(msgId, receiveBytes);

            if (message == null)
            {
                if (!_badPacketBans.ContainsKey(senderEndpoint.Address))
                {
                    _badPacketBans.Add(senderEndpoint.Address, true);
                }
                Log.ErrorFormat("Receive bad packet with ID: {0} (0x{0:x2}) {2} from {1}", msgId, senderEndpoint.Address, (DefaultMessageIdTypes)msgId);
                return;
            }

            message.Source = "RakNet";

            TraceReceive(message);

            switch (msgIdType)
            {
            case DefaultMessageIdTypes.ID_UNCONNECTED_PING:
            case DefaultMessageIdTypes.ID_UNCONNECTED_PING_OPEN_CONNECTIONS:
            {
                UnconnectedPing incoming = (UnconnectedPing)message;

                //TODO: This needs to be verified with RakNet first
                //response.sendpingtime = msg.sendpingtime;
                //response.sendpongtime = DateTimeOffset.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                var packet = UnconnectedPong.CreateObject();
                packet.serverId   = 22345;
                packet.pingId     = incoming.pingId;
                packet.serverName = MotdProvider.GetMotd(ServerInfo);
                var data = packet.Encode();
                packet.PutPool();
                TraceSend(packet);
                SendData(data, senderEndpoint, new object());
                break;
            }

            case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_1:
            {
                OpenConnectionRequest1 incoming = (OpenConnectionRequest1)message;
                Log.DebugFormat("New connection from: {0} {1}", senderEndpoint.Address, senderEndpoint.Port);

                lock (_playerSessions)
                {
                    // Already connecting, then this is just a duplicate
                    if (_connectionAttemps.ContainsKey(senderEndpoint))
                    {
                        DateTime created;
                        _connectionAttemps.TryGetValue(senderEndpoint, out created);

                        if (DateTime.UtcNow < created + TimeSpan.FromSeconds(3))
                        {
                            return;
                        }
                    }

                    //PlayerNetworkSession session;
                    //if (_playerSessions.TryGetValue(senderEndpoint, out session))
                    //{

                    //	Log.DebugFormat("Reconnection detected from {0}. Removing old session and disconnecting old player.", senderEndpoint.Address);

                    //	Player oldPlayer = session.Player;
                    //	if (oldPlayer != null)
                    //	{
                    //		oldPlayer.Disconnect("Reconnecting.");
                    //	}
                    //	else
                    //	{
                    //		_playerSessions.TryRemove(session.EndPoint, out session);
                    //	}
                    //}

                    if (!_connectionAttemps.ContainsKey(senderEndpoint))
                    {
                        _connectionAttemps.Add(senderEndpoint, DateTime.UtcNow);
                    }
                }

                var packet = OpenConnectionReply1.CreateObject();
                packet.serverGuid        = 12345;
                packet.mtuSize           = incoming.mtuSize;
                packet.serverHasSecurity = 0;
                var data = packet.Encode();
                packet.PutPool();

                TraceSend(packet);

                SendData(data, senderEndpoint, new object());
                break;
            }

            case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_2:
            {
                OpenConnectionRequest2 incoming = (OpenConnectionRequest2)message;

                PlayerNetworkSession session;
                lock (_playerSessions)
                {
                    if (_connectionAttemps.ContainsKey(senderEndpoint))
                    {
                        _connectionAttemps.Remove(senderEndpoint);
                    }
                    else
                    {
                        Log.ErrorFormat("Unexpected connection request packet from {0}.", senderEndpoint.Address);
                        return;
                    }

                    //PlayerNetworkSession session;
                    if (_playerSessions.TryGetValue(senderEndpoint, out session))
                    {
                        Log.WarnFormat("Reconnection detected from {0}. Removing old session and disconnecting old player.", senderEndpoint.Address);

                        Player oldPlayer = session.Player;
                        if (oldPlayer != null)
                        {
                            oldPlayer.Disconnect("Reconnecting.");
                        }
                        else
                        {
                            _playerSessions.TryRemove(session.EndPoint, out session);
                        }
                    }


                    if (_playerSessions.TryGetValue(senderEndpoint, out session))
                    {
                        // Already connecting, then this is just a duplicate
                        if (session.State == ConnectionState.Connecting /* && DateTime.UtcNow < session.LastUpdatedTime + TimeSpan.FromSeconds(2)*/)
                        {
                            return;
                        }

                        Log.ErrorFormat("Unexpected session from {0}. Removing old session and disconnecting old player.", senderEndpoint.Address);

                        Player oldPlayer = session.Player;
                        if (oldPlayer != null)
                        {
                            oldPlayer.Disconnect("Reconnecting.");
                        }
                        else
                        {
                            _playerSessions.TryRemove(session.EndPoint, out session);
                        }
                    }

                    session = new PlayerNetworkSession(null, senderEndpoint)
                    {
                        State           = ConnectionState.Connecting,
                        LastUpdatedTime = DateTime.UtcNow,
                        Mtuize          = incoming.mtuSize
                    };

                    _playerSessions.TryAdd(senderEndpoint, session);
                }

                Player player = PlayerFactory.CreatePlayer(this, senderEndpoint, incoming.mtuSize);
                player.ClientGuid     = incoming.clientGuid;
                player.NetworkSession = session;
                session.Player        = player;

                var reply = OpenConnectionReply2.CreateObject();
                reply.serverGuid             = 12345;
                reply.mtuSize                = incoming.mtuSize;
                reply.doSecurityAndHandshake = new byte[0];
                var data = reply.Encode();
                reply.PutPool();

                TraceSend(reply);

                SendData(data, senderEndpoint, session.SyncRoot);
                break;
            }

            default:
                if (!_badPacketBans.ContainsKey(senderEndpoint.Address))
                {
                    _badPacketBans.Add(senderEndpoint.Address, true);
                }
                Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) {2} from {1}", msgId, senderEndpoint.Address, (DefaultMessageIdTypes)msgId);
                break;
            }

            message.PutPool();
        }
Exemple #10
0
        private void ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint)
        {
            byte msgId = receiveBytes[0];

            if (msgId == 0xFE)
            {
                Log.InfoFormat("A query detected from: {0}", senderEndpoint.Address);
                HandleQuery(receiveBytes, senderEndpoint);
            }
            else if (msgId <= (byte)DefaultMessageIdTypes.ID_USER_PACKET_ENUM)
            {
                HandleRakNetMessage(receiveBytes, senderEndpoint, msgId);
            }
            else
            {
                PlayerNetworkSession playerSession;
                if (!_playerSessions.TryGetValue(senderEndpoint, out playerSession))
                {
                    Log.DebugFormat("Receive MCPE message 0x{1:x2} without session {0}", senderEndpoint.Address, msgId);
                    return;
                }

                Player player = playerSession.Player;

                if (player == null)
                {
                    Log.ErrorFormat("Receive MCPE message 0x{1:x2} without player {0}. Session removed.", senderEndpoint.Address, msgId);
                    _playerSessions.TryRemove(senderEndpoint, out playerSession);
                    return;
                }

                if (playerSession.Evicted)
                {
                    return;
                }

                playerSession.LastUpdatedTime = DateTime.UtcNow;

                DatagramHeader header = new DatagramHeader(receiveBytes[0]);
                if (!header.isACK && !header.isNAK && header.isValid)
                {
                    if (receiveBytes[0] == 0xa0)
                    {
                        throw new Exception("Receive ERROR, NAK in wrong place");
                    }

                    ConnectedPackage package = ConnectedPackage.CreateObject();
                    try
                    {
                        package.Decode(receiveBytes);
                    }
                    catch (Exception e)
                    {
                        player.Disconnect("Bad package received from client.");
                        return;
                    }


                    // IF reliable code below is enabled, useItem start sending doubles
                    // for some unknown reason.

                    //Reliability reliability = package._reliability;
                    //if (reliability == Reliability.Reliable
                    //	|| reliability == Reliability.ReliableSequenced
                    //	|| reliability == Reliability.ReliableOrdered
                    //	)
                    {
                        EnqueueAck(playerSession, package._datagramSequenceNumber);
                    }

                    List <Package> messages = package.Messages;

                    if (messages.Count == 1)
                    {
                        McpeBatch batch = messages.First() as McpeBatch;
                        if (batch != null)
                        {
                            batch.Source = "Client";
                            messages.Clear();

                            // Get bytes
                            byte[] payload = batch.payload;
                            // Decompress bytes

                            MemoryStream stream = new MemoryStream(payload);
                            if (stream.ReadByte() != 0x78)
                            {
                                throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C");
                            }
                            stream.ReadByte();
                            using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false))
                            {
                                // Get actual package out of bytes
                                MemoryStream destination = new MemoryStream();
                                defStream2.CopyTo(destination);
                                byte[] internalBuffer = destination.ToArray();
                                messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer));
                            }
                            batch.PutPool();
                        }
                    }

                    DelayedProcessing(playerSession, package);
                    package.PutPool();
                }
                else if (header.isACK && header.isValid)
                {
                    ServerInfo.NumberOfAckReceive++;
                    HandleAck(playerSession, receiveBytes);
                }
                else if (header.isNAK && header.isValid)
                {
                    ServerInfo.NumberOfNakReceive++;
                    HandleNak(playerSession, receiveBytes);
                }
                else if (!header.isValid)
                {
                    Log.Warn("!!!! ERROR, Invalid header !!!!!");
                }
            }
        }
Exemple #11
0
        private void Update(object state)
        {
            if (!Monitor.TryEnter(_updateGlobalLock))
            {
                return;
            }

            try
            {
                long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                Parallel.ForEach(_playerSessions.Values.ToArray(), delegate(PlayerNetworkSession session)
                {
                    if (session == null)
                    {
                        return;
                    }
                    if (session.Evicted)
                    {
                        return;
                    }

                    try
                    {
                        Player player = session.Player;

                        long lastUpdate = session.LastUpdatedTime.Ticks / TimeSpan.TicksPerMillisecond;
                        if (lastUpdate + InacvitityTimeout + 3000 + Math.Min(5000, ServerInfo.AvailableBytes) < now)
                        {
                            session.Evicted = true;
                            // Disconnect user
                            ThreadPool.QueueUserWorkItem(delegate(object o)
                            {
                                PlayerNetworkSession s = o as PlayerNetworkSession;
                                if (s != null)
                                {
                                    Player p = s.Player;
                                    if (p != null)
                                    {
                                        p.Disconnect("You've been kicked with reason: Network timeout.");
                                    }
                                    else
                                    {
                                        if (ServerInfo.PlayerSessions.TryRemove(session.EndPoint, out session))
                                        {
                                            session.Player  = null;
                                            session.State   = ConnectionState.Unconnected;
                                            session.Evicted = true;
                                            session.Clean();
                                        }
                                    }
                                }
                            }, session);

                            return;
                        }


                        if (session.State != ConnectionState.Connected && player != null && lastUpdate + 3000 < now)
                        {
                            ThreadPool.QueueUserWorkItem(delegate(object o)
                            {
                                PlayerNetworkSession s = o as PlayerNetworkSession;
                                if (s != null)
                                {
                                    Player p = s.Player;
                                    if (p != null)
                                    {
                                        p.Disconnect("You've been kicked with reason: Lost connection.");
                                    }
                                }
                            }, session);

                            return;
                        }

                        if (player == null)
                        {
                            return;
                        }

                        if (lastUpdate + InacvitityTimeout < now)
                        {
                            player.DetectLostConnection();
                        }

                        long rto  = Math.Max(100, player.Rto);
                        var queue = session.WaitingForAcksQueue;
                        foreach (var datagram in queue.Values)
                        {
                            if (!datagram.Timer.IsRunning)
                            {
                                Log.ErrorFormat("Timer not running for #{0}", datagram.Header.datagramSequenceNumber);
                                datagram.Timer.Restart();
                                continue;
                            }

                            if (player.Rtt == -1)
                            {
                                continue;
                            }

                            long elapsedTime = datagram.Timer.ElapsedMilliseconds;
                            if (elapsedTime >= rto * (datagram.TransmissionCount + 2))
                            {
                                Datagram deleted;
                                if (queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted))
                                {
                                    session.ErrorCount++;

                                    if (deleted.TransmissionCount > 1)
                                    {
                                        Log.DebugFormat("Remove from ACK queue #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTT {5}",
                                                        deleted.Header.datagramSequenceNumber.IntValue(),
                                                        player.Username,
                                                        deleted.FirstMessageId,
                                                        elapsedTime,
                                                        rto,
                                                        player.Rtt);


                                        foreach (MessagePart part in deleted.MessageParts)
                                        {
                                            part.PutPool();
                                        }
                                        deleted.PutPool();

                                        continue;
                                    }

                                    if (!session.Evicted)
                                    {
                                        ThreadPool.QueueUserWorkItem(delegate(object data)
                                        {
                                            try
                                            {
                                                Log.DebugFormat("Resent #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTT {5}",
                                                                deleted.Header.datagramSequenceNumber.IntValue(),
                                                                player.Username,
                                                                deleted.FirstMessageId,
                                                                elapsedTime,
                                                                rto,
                                                                player.Rtt);
                                                SendDatagram(session, (Datagram)data);
                                            }
                                            catch (Exception e)
                                            {
                                            }
                                        }, datagram);
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                    }
                });
            }
            finally
            {
                Monitor.Exit(_updateGlobalLock);
            }
        }
Exemple #12
0
        private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage, Player player)
        {
            int spId    = package._splitPacketId;
            int spIdx   = package._splitPacketIndex;
            int spCount = package._splitPacketCount;

            if (!playerSession.Splits.ContainsKey(spId))
            {
                playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]);
            }

            SplitPartPackage[] spPackets = playerSession.Splits[spId];
            spPackets[spIdx] = splitMessage;

            bool haveEmpty = false;

            for (int i = 0; i < spPackets.Length; i++)
            {
                haveEmpty = haveEmpty || spPackets[i] == null;
            }

            if (!haveEmpty)
            {
                Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

                SplitPartPackage[] waste;
                playerSession.Splits.TryRemove(spId, out waste);

                MemoryStream stream = MemoryStreamManager.GetStream();
                for (int i = 0; i < spPackets.Length; i++)
                {
                    SplitPartPackage splitPartPackage = spPackets[i];
                    byte[]           buf = splitPartPackage.Message;
                    if (buf == null)
                    {
                        Log.Error("Expected bytes in splitpart, but got none");
                        continue;
                    }

                    stream.Write(buf, 0, buf.Length);
                    splitPartPackage.PutPool();
                }

                byte[] buffer = stream.ToArray();
                try
                {
                    ConnectedPackage newPackage = ConnectedPackage.CreateObject();
                    newPackage._datagramSequenceNumber = package._datagramSequenceNumber;
                    newPackage._reliability            = package._reliability;
                    newPackage._reliableMessageNumber  = package._reliableMessageNumber;
                    newPackage._sequencingIndex        = package._sequencingIndex;
                    newPackage._orderingIndex          = package._orderingIndex;
                    newPackage._orderingChannel        = package._orderingChannel;
                    newPackage._hasSplit = false;

                    Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer, "raknet") ?? new UnknownPackage(buffer[0], buffer);
                    fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
                    fullMessage.Reliability            = package._reliability;
                    fullMessage.ReliableMessageNumber  = package._reliableMessageNumber;
                    fullMessage.OrderingIndex          = package._orderingIndex;
                    fullMessage.OrderingChannel        = package._orderingChannel;

                    newPackage.Messages = new List <Package>();
                    newPackage.Messages.Add(fullMessage);

                    Log.Debug($"Assembled split package {newPackage._reliability} message #{newPackage._reliableMessageNumber}, Chan: #{newPackage._orderingChannel}, OrdIdx: #{newPackage._orderingIndex}");
                    HandleConnectedPackage(playerSession, newPackage);
                    newPackage.PutPool();
                }
                catch (Exception e)
                {
                    Log.Error("Error during split message parsing", e);
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"0x{buffer[0]:x2}\n{Package.HexDump(buffer)}");
                    }
                    player.Disconnect("Bad package received from client.");
                }
            }
        }