Example #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.");
                }
            }
        }
Example #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);

                    session.Disconnect("Reconnecting.", false);

                    _playerSessions.TryRemove(senderEndpoint, out session);
                }

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

                _playerSessions.TryAdd(senderEndpoint, session);
            }

            //Player player = PlayerFactory.CreatePlayer(this, senderEndpoint);
            //player.ClientGuid = incoming.clientGuid;
            //player.NetworkHandler = session;
            //session.Player = player;
            session.MessageHandler = new LoginMessageHandler(session);

            var reply = OpenConnectionReply2.CreateObject();

            reply.serverGuid             = MotdProvider.ServerId;
            reply.clientEndpoint         = senderEndpoint;
            reply.mtuSize                = incoming.mtuSize;
            reply.doSecurityAndHandshake = new byte[1];
            var data = reply.Encode();

            TraceSend(reply);

            reply.PutPool();


            SendData(data, senderEndpoint);
        }
Example #3
0
		private void SendAckQueue(object state)
		{
			var sessions = _playerSessions.Values.ToArray();

			foreach (var s in sessions)
			{
				ThreadPool.QueueUserWorkItem(delegate(object o)
				{
					PlayerNetworkSession session = (PlayerNetworkSession) o;
					var queue = session.PlayerAckQueue;
					int lenght = queue.Count;

					if (lenght == 0) return;

					Acks acks = Acks.CreateObject();
					for (int i = 0; i < lenght; i++)
					{
						int ack;
						if (!session.PlayerAckQueue.TryDequeue(out ack)) break;

						acks.acks.Add(ack);
					}

					if (acks.acks.Count > 0)
					{
						byte[] data = acks.Encode();
						SendData(data, session.EndPoint);
					}

					acks.PutPool();
				}, s);
			}
		}
Example #4
0
        private void SendAckQueue()
        {
            PlayerNetworkSession session = this;
            var queue  = session.PlayerAckQueue;
            int lenght = queue.Count;

            if (lenght == 0)
            {
                return;
            }

            Acks acks = Acks.CreateObject();

            //Acks acks = new Acks();
            for (int i = 0; i < lenght; i++)
            {
                int ack;
                if (!session.PlayerAckQueue.TryDequeue(out ack))
                {
                    break;
                }

                Interlocked.Increment(ref Server.ServerInfo.NumberOfAckSent);
                acks.acks.Add(ack);
            }

            if (acks.acks.Count > 0)
            {
                byte[] data = acks.Encode();
                Server.SendData(data, session.EndPoint);
            }

            acks.PutPool();
        }
Example #5
0
        internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            Player player = playerSession.Player;

            if (message == null)
            {
                return;
            }

            TraceReceive(message, message.DatagramSequenceNumber);

            if (message.Reliability == Reliability.ReliableOrdered)
            {
                playerSession.AddToProcessing(message);
                return;
            }

            if (typeof(UnknownPackage) == message.GetType())
            {
                UnknownPackage packet = (UnknownPackage)message;
                Log.Warn($"Received unknown package 0x{message.Id:X2}\n{Package.HexDump(packet.Message)}");
                message.PutPool();
                return;
            }

            player?.HandlePackage(message);
            message.PutPool();
        }
Example #6
0
        private void SendDatagram(PlayerNetworkSession session, Datagram datagram)
        {
            if (datagram.MessageParts.Count == 0)
            {
                datagram.PutPool();
                Log.WarnFormat("Failed to resend #{0}", datagram.Header.datagramSequenceNumber.IntValue());
                return;
            }

            datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref session.DatagramSequenceNumber);

            datagram.TransmissionCount++;

            byte[] data = datagram.Encode();

            datagram.Timer.Restart();

            if (!session.WaitingForAcksQueue.TryAdd(datagram.Header.datagramSequenceNumber.IntValue(), datagram))
            {
                Log.Warn(string.Format("Datagram sequence unexpectedly existed in the ACK/NAK queue already {0}", datagram.Header.datagramSequenceNumber.IntValue()));
            }
            //datagram.PutPool();

            lock (session.SyncRoot)
            {
                SendData(data, session.EndPoint);
            }
        }
Example #7
0
        private void DelayedProcessing(PlayerNetworkSession playerSession, ConnectedPackage package)
        {
            Player player = playerSession.Player;

            if (ForwardAllPlayers)
            {
                var transfer = McpeTransfer.CreateObject();
                transfer.endpoint = ForwardTarget;
                player.SendPackage(transfer, true);

                return;
            }

            List <Package> messages = package.Messages;

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

                if (message is SplitPartPackage)
                {
                    HandleSplitMessage(playerSession, package, (SplitPartPackage)message, player);

                    continue;
                }

                message.Timer.Restart();
                HandlePackage(message, playerSession);
                message.PutPool();                 // Handled in HandlePacket now()
            }
        }
Example #8
0
        internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            if (message == null)
            {
                return;
            }

            TraceReceive(message);

            if (typeof(UnknownPackage) == message.GetType())
            {
                return;
            }

            if (typeof(McpeBatch) == message.GetType())
            {
                McpeBatch batch = (McpeBatch)message;

                var messages = new List <Package>();

                // 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));
                }
                foreach (var msg in messages)
                {
                    msg.DatagramSequenceNumber = batch.DatagramSequenceNumber;
                    msg.OrderingChannel        = batch.OrderingChannel;
                    msg.OrderingIndex          = batch.OrderingIndex;
                    HandlePackage(msg, playerSession);
                    msg.PutPool();
                }

                return;
            }

            message.Source = "HandlePackage";

            Player player = playerSession.Player;

            if (player != null)
            {
                player.HandlePackage(message);
            }
        }
Example #9
0
        public void SendPackage(PlayerNetworkSession session, Package message)
        {
            foreach (var datagram in Datagram.CreateDatagrams(message, session.MtuSize, session))
            {
                SendDatagram(session, datagram);
            }

            message.PutPool();
        }
Example #10
0
        private void HandleAck(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null)
            {
                return;
            }

            //Ack ack = Ack.CreateObject();
            Ack ack = new Ack();

            //ack.Reset();
            ack.Decode(receiveBytes);

            var queue = session.WaitingForAcksQueue;

            foreach (Tuple <int, int> range in ack.ranges)
            {
                Interlocked.Increment(ref ServerInfo.NumberOfAckReceive);

                int start = range.Item1;
                int end   = range.Item2;
                for (int i = start; i <= end; i++)
                {
                    Datagram datagram;
                    if (queue.TryRemove(i, out datagram))
                    {
                        //if (Log.IsDebugEnabled)
                        //	Log.DebugFormat("ACK, on datagram #{0} for {2}. Queue size={1}", i, queue.Count, player.Username);

                        // RTT = RTT * 0.875 + rtt * 0.125
                        // RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
                        // RTO = RTT + 4 * RTTVar
                        long rtt    = datagram.Timer.ElapsedMilliseconds;
                        long RTT    = session.Rtt;
                        long RTTVar = session.RttVar;

                        session.Rtt    = (long)(RTT * 0.875 + rtt * 0.125);
                        session.RttVar = (long)(RTTVar * 0.875 + Math.Abs(RTT - rtt) * 0.125);
                        session.Rto    = session.Rtt + 4 * session.RttVar + 100;                    // SYNC time in the end

                        datagram.PutPool();
                    }
                    else
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.WarnFormat("ACK, Failed to remove datagram #{0} for {2}. Queue size={1}", i, queue.Count, session.Username);
                        }
                    }
                }
            }

            //ack.PutPool();

            session.ResendCount = 0;
            session.WaitForAck  = false;
        }
Example #11
0
        private void HandleNak(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null)
            {
                return;
            }

            Player player = session.Player;

            if (player == null)
            {
                return;
            }

            Nak nak = Nak.CreateObject();

            nak.Decode(receiveBytes);

            int ackSeqNo   = nak.sequenceNumber.IntValue();
            int toAckSeqNo = nak.toSequenceNumber.IntValue();

            if (nak.onlyOneSequence == 1)
            {
                toAckSeqNo = ackSeqNo;
            }

            nak.PutPool();

            var queue = session.WaitingForAcksQueue;

            Log.DebugFormat("NAK from Player {0} ({5}) #{1}-{2} IsOnlyOne {3} Count={4}", player.Username, ackSeqNo, toAckSeqNo, nak.onlyOneSequence, nak.count, player.Rtt);

            for (int i = ackSeqNo; i <= toAckSeqNo; i++)
            {
                session.ErrorCount++;

                Datagram datagram;
                if (queue.TryRemove(i, out datagram))
                {
                    // RTT = RTT * 0.875 + rtt * 0.125
                    // RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
                    // RTO = RTT + 4 * RTTVar
                    long rtt    = datagram.Timer.ElapsedMilliseconds;
                    long RTT    = player.Rtt;
                    long RTTVar = player.RttVar;

                    player.Rtt    = (long)(RTT * 0.875 + rtt * 0.125);
                    player.RttVar = (long)(RTTVar * 0.875 + Math.Abs(RTT - rtt) * 0.125);
                    player.Rto    = player.Rtt + 4 * player.RttVar + 10;                // SYNC time in the end
                    SendDatagram(session, datagram);
                }
                else
                {
                    Log.DebugFormat("NAK, no datagram #{0} to resend for {1}", i, player.Username);
                }
            }
        }
Example #12
0
		private void HandleNak(PlayerNetworkSession session, byte[] receiveBytes)
		{
			if (session == null) return;

			Player player = session.Player;
			if (player == null) return;

			Nak nak = Nak.CreateObject();
			nak.Reset();
			nak.Decode(receiveBytes);

			var queue = session.WaitingForAcksQueue;

			foreach (Tuple<int, int> range in nak.ranges)
			{
				ServerInfo.NumberOfNakReceive++;

				int start = range.Item1;
				int end = range.Item2;

				for (int i = start; i <= end; i++)
				{
					session.ErrorCount++;

					// HACK: Just to make sure we aren't getting unessecary load on the queue during heavy buffering.
					if (ServerInfo.AvailableBytes > 1000) continue;

					Datagram datagram;
					if (queue.TryGetValue(i, out datagram))
					{
						// RTT = RTT * 0.875 + rtt * 0.125
						// RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
						// RTO = RTT + 4 * RTTVar
						long rtt = datagram.Timer.ElapsedMilliseconds;
						long RTT = player.Rtt;
						long RTTVar = player.RttVar;

						player.Rtt = (long) (RTT*0.875 + rtt*0.125);
						player.RttVar = (long) (RTTVar*0.875 + Math.Abs(RTT - rtt)*0.125);
						player.Rto = player.Rtt + 4*player.RttVar + 100; // SYNC time in the end

						//if (Log.IsDebugEnabled)
						//	Log.ErrorFormat("NAK, resending datagram #{0} for {1}, MTU: {2}", i, player.Username, session.Mtuize);

						//SendDatagram(session, datagram, false);
					}
					else
					{
						if (Log.IsDebugEnabled)
							//Log.WarnFormat("NAK, no datagram #{0} to resend for {1}", i, player.Username);
					}
				}
			}

			nak.PutPool();
		}
Example #13
0
        private static void CalculateRto(PlayerNetworkSession session, Datagram datagram)
        {
            // RTT = RTT * 0.875 + rtt * 0.125
            // RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
            // RTO = RTT + 4 * RTTVar
            long rtt    = datagram.Timer.ElapsedMilliseconds;
            long RTT    = session.Rtt;
            long RTTVar = session.RttVar;

            session.Rtt    = (long)(RTT * 0.875 + rtt * 0.125);
            session.RttVar = (long)(RTTVar * 0.875 + Math.Abs(RTT - rtt) * 0.125);
            session.Rto    = session.Rtt + 4 * session.RttVar + 100;        // SYNC time in the end
        }
Example #14
0
        private void HandleConnectedPackage(PlayerNetworkSession playerSession, ConnectedPackage package)
        {
            foreach (var message in package.Messages)
            {
                if (message is SplitPartPackage)
                {
                    HandleSplitMessage(playerSession, (SplitPartPackage)message);
                    continue;
                }

                message.Timer.Restart();
                HandlePackage(message, playerSession);
            }
        }
Example #15
0
        /// <summary>
        ///     Handles the specified package.
        /// </summary>
        /// <param name="message">The package.</param>
        /// <param name="senderEndpoint">The sender's endpoint.</param>
        private void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            TraceReceive(message);

            if (typeof(UnknownPackage) == message.GetType())
            {
                return;
            }

            if (typeof(McpeBatch) == message.GetType())
            {
                McpeBatch batch = (McpeBatch)message;

                var messages = new List <Package>();

                // 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));
                }
                foreach (var msg in messages)
                {
                    HandlePackage(msg, playerSession);
                }
            }

            playerSession.Player.HandlePackage(message);
            playerSession.LastUpdatedTime = DateTime.UtcNow;

            if (typeof(DisconnectionNotification) == message.GetType())
            {
                PlayerNetworkSession value;
                _playerSessions.TryRemove(playerSession.EndPoint, out value);
            }
        }
Example #16
0
        private void HandleAck(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null)
            {
                return;
            }

            //Ack ack = Ack.CreateObject();
            Ack ack = new Ack();

            //ack.Reset();
            ack.Decode(receiveBytes);

            var queue = session.WaitingForAcksQueue;

            foreach (Tuple <int, int> range in ack.ranges)
            {
                Interlocked.Increment(ref ServerInfo.NumberOfAckReceive);

                int start = range.Item1;
                int end   = range.Item2;
                for (int i = start; i <= end; i++)
                {
                    if (queue.TryRemove(i, out var datagram))
                    {
                        //if (Log.IsDebugEnabled)
                        //	Log.DebugFormat("ACK, on datagram #{0} for {2}. Queue size={1}", i, queue.Count, player.Username);

                        CalculateRto(session, datagram);

                        datagram.PutPool();
                    }
                    else
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.WarnFormat("ACK, Failed to remove datagram #{0} for {2}. Queue size={1}", i, queue.Count, session.Username);
                        }
                    }
                }
            }

            //ack.PutPool();

            session.ResendCount = 0;
            session.WaitForAck  = false;
        }
Example #17
0
        internal void SendDatagram(PlayerNetworkSession session, Datagram datagram)
        {
            if (datagram.MessageParts.Count == 0)
            {
                datagram.PutPool();
                Log.WarnFormat("Failed to resend #{0}", datagram.Header.datagramSequenceNumber.IntValue());
                return;
            }

            if (datagram.TransmissionCount > 10)
            {
                if (Log.IsDebugEnabled)
                {
                    Log.WarnFormat("Retransmission count exceeded. No more resend of #{0} Type: {2} (0x{2:x2}) for {1}",
                                   datagram.Header.datagramSequenceNumber.IntValue(),
                                   session.Username,
                                   datagram.FirstMessageId);
                }

                datagram.PutPool();

                Interlocked.Increment(ref ServerInfo.NumberOfFails);
                return;
            }

            datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref session.DatagramSequenceNumber);
            datagram.TransmissionCount++;
            datagram.RetransmitImmediate = false;

            //byte[] data = datagram.Encode();
            byte[] data;
            var    lenght = (int)datagram.GetEncoded(out data);

            datagram.Timer.Restart();

            if (!session.WaitingForAcksQueue.TryAdd(datagram.Header.datagramSequenceNumber.IntValue(), datagram))
            {
                Log.Warn(string.Format("Datagram sequence unexpectedly existed in the ACK/NAK queue already {0}", datagram.Header.datagramSequenceNumber.IntValue()));
            }

            lock (session.SyncRoot)
            {
                SendData(data, lenght, session.EndPoint);
            }
        }
Example #18
0
        private void HandleConnectedPackage(PlayerNetworkSession playerSession, ConnectedPackage package)
        {
            Player player = playerSession.Player;

            List <Package> messages = package.Messages;

            foreach (var message in messages)
            {
                if (message is SplitPartPackage)
                {
                    HandleSplitMessage(playerSession, package, (SplitPartPackage)message, player);
                    continue;
                }

                message.Timer.Restart();
                HandlePackage(message, playerSession);
            }
        }
Example #19
0
        internal void SendDatagram(PlayerNetworkSession session, Datagram datagram)
        {
            if (datagram.MessageParts.Count == 0)
            {
                datagram.PutPool();
                Log.WarnFormat("Failed to resend #{0}", datagram.Header.datagramSequenceNumber.IntValue());
                return;
            }

            if (datagram.TransmissionCount > 10)
            {
                if (Log.IsDebugEnabled)
                {
                    Log.WarnFormat("TIMEOUT, Retransmission count remove from ACK queue #{0} Type: {2} (0x{2:x2}) for {1}",
                                   datagram.Header.datagramSequenceNumber.IntValue(),
                                   session.Username,
                                   datagram.FirstMessageId);
                }

                datagram.PutPool();

                Interlocked.Increment(ref ServerInfo.NumberOfFails);
                return;
            }

            datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref session.DatagramSequenceNumber);
            datagram.TransmissionCount++;

            byte[] data = datagram.Encode();

            datagram.Timer.Restart();

            if (!session.WaitingForAcksQueue.TryAdd(datagram.Header.datagramSequenceNumber.IntValue(), datagram))
            {
                Log.Warn(string.Format("Datagram sequence unexpectedly existed in the ACK/NAK queue already {0}", datagram.Header.datagramSequenceNumber.IntValue()));
            }

            lock (session.SyncRoot)
            {
                SendData(data, session.EndPoint);
                Thread.Sleep(12);
            }
        }
Example #20
0
        private void HandleNak(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null)
            {
                return;
            }

            Nak nak = Nak.CreateObject();

            nak.Reset();
            nak.Decode(receiveBytes);

            var queue = session.WaitingForAcksQueue;

            foreach (Tuple <int, int> range in nak.ranges)
            {
                Interlocked.Increment(ref ServerInfo.NumberOfNakReceive);

                int start = range.Item1;
                int end   = range.Item2;

                for (int i = start; i <= end; i++)
                {
                    if (queue.TryGetValue(i, out var datagram))
                    {
                        CalculateRto(session, datagram);

                        datagram.RetransmitImmediate = true;
                    }
                    else
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.WarnFormat("NAK, no datagram #{0} for {1}", i, session.Username);
                        }
                    }
                }
            }

            nak.PutPool();
        }
Example #21
0
        internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            if (message == null)
            {
                return;
            }

            if (message.Reliability == Reliability.ReliableOrdered)
            {
                if (ForceOrderingForAll == false && (playerSession.CryptoContext == null || playerSession.CryptoContext.UseEncryption == false))
                {
                    playerSession.AddToProcessing(message);
                }
                else
                {
                    FastThreadPool.QueueUserWorkItem(() => playerSession.AddToProcessing(message));
                }

                return;
            }

            playerSession.HandlePackage(message, playerSession);
        }
Example #22
0
		private void HandleAck(PlayerNetworkSession session, byte[] receiveBytes)
		{
			if (session == null) return;

			Player player = session.Player;
			if (player == null) return;

			Ack ack = Ack.CreateObject();
			ack.Reset();
			ack.Decode(receiveBytes);

			var queue = session.WaitingForAcksQueue;

			foreach (Tuple<int, int> range in ack.ranges)
			{
				ServerInfo.NumberOfAckReceive++;

				int start = range.Item1;
				int end = range.Item2;
				for (int i = start; i <= end; i++)
				{
					Datagram datagram;
					if (queue.TryRemove(i, out datagram))
					{
						//if (Log.IsDebugEnabled)
						//	Log.DebugFormat("ACK, on datagram #{0} for {2}. Queue size={1}", i, queue.Count, player.Username);

						// RTT = RTT * 0.875 + rtt * 0.125
						// RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
						// RTO = RTT + 4 * RTTVar
						long rtt = datagram.Timer.ElapsedMilliseconds;
						long RTT = player.Rtt;
						long RTTVar = player.RttVar;

						player.Rtt = (long) (RTT*0.875 + rtt*0.125);
						player.RttVar = (long) (RTTVar*0.875 + Math.Abs(RTT - rtt)*0.125);
						player.Rto = player.Rtt + 4*player.RttVar + 100; // SYNC time in the end

						datagram.PutPool();
					}
					else
					{
						if (Log.IsDebugEnabled)
							Log.WarnFormat("ACK, Failed to remove datagram #{0} for {2}. Queue size={1}", i, queue.Count, player.Username);
					}
				}
			}

			ack.PutPool();

			session.ResendCount = 0;
			session.WaitForAck = false;
		}
Example #23
0
		private void HandleNak(PlayerNetworkSession session, byte[] receiveBytes)
		{
			if (session == null) return;

			Player player = session.Player;
			if (player == null) return;

			Nak nak = Nak.CreateObject();
			nak.Reset();
			nak.Decode(receiveBytes);

			var queue = session.WaitingForAcksQueue;

			foreach (Tuple<int, int> range in nak.ranges)
			{
				ServerInfo.NumberOfNakReceive++;

				int start = range.Item1;
				int end = range.Item2;

				for (int i = start; i <= end; i++)
				{
					session.ErrorCount++;

					// HACK: Just to make sure we aren't getting unessecary load on the queue during heavy buffering.
					if (ServerInfo.AvailableBytes > 1000) continue;

					Datagram datagram;
					if (queue.TryGetValue(i, out datagram))
					{
						// RTT = RTT * 0.875 + rtt * 0.125
						// RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
						// RTO = RTT + 4 * RTTVar
						long rtt = datagram.Timer.ElapsedMilliseconds;
						long RTT = player.Rtt;
						long RTTVar = player.RttVar;

						player.Rtt = (long) (RTT*0.875 + rtt*0.125);
						player.RttVar = (long) (RTTVar*0.875 + Math.Abs(RTT - rtt)*0.125);
						player.Rto = player.Rtt + 4*player.RttVar + 100; // SYNC time in the end

						//if (Log.IsDebugEnabled)
						//	Log.ErrorFormat("NAK, resending datagram #{0} for {1}, MTU: {2}", i, player.Username, session.Mtuize);

						//SendDatagram(session, datagram, false);
					}
					else
					{
						if (Log.IsDebugEnabled)
							Log.WarnFormat("NAK, no datagram #{0} to resend for {1}", i, player.Username);
					}
				}
			}

			nak.PutPool();
		}
Example #24
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.");
				}
			}
		}
Example #25
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.ReliableMessageNumber = package._reliableMessageNumber;
				//message.OrderingChannel = package._orderingChannel;
				//message.OrderingIndex = package._orderingIndex;

				if (message is SplitPartPackage)
				{
					HandleSplitMessage(playerSession, package, (SplitPartPackage) message, player);

					continue;
				}

				message.Timer.Restart();
				HandlePackage(message, playerSession);
				message.PutPool(); // Handled in HandlePacket now()
			}
		}
Example #26
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;
					if (oldPlayer != null)
					{
						oldPlayer.Disconnect("Reconnecting.", false);
					}

					_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.clientendpoint = senderEndpoint;
			reply.mtuSize = incoming.mtuSize;
			reply.doSecurityAndHandshake = new byte[1];
			var data = reply.Encode();
			reply.PutPool();

			TraceSend(reply);

			SendData(data, senderEndpoint);
		}
Example #27
0
        private void HandleNak(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null) return;

            Player player = session.Player;
            if (player == null) return;

            Nak nak = Nak.CreateObject();
            nak.Decode(receiveBytes);

            int ackSeqNo = nak.sequenceNumber.IntValue();
            int toAckSeqNo = nak.toSequenceNumber.IntValue();
            if (nak.onlyOneSequence == 1) toAckSeqNo = ackSeqNo;

            nak.PutPool();

            var queue = session.WaitingForAcksQueue;

            if (Log.IsDebugEnabled)
                Log.DebugFormat("NAK from Player {0} ({5}) #{1}-{2} IsOnlyOne {3} Count={4}", player.Username, ackSeqNo, toAckSeqNo, nak.onlyOneSequence, nak.count, player.Rtt);

            for (int i = ackSeqNo; i <= toAckSeqNo; i++)
            {
                session.ErrorCount++;

                Datagram datagram;
                if (queue.TryRemove(i, out datagram))
                {
                    // RTT = RTT * 0.875 + rtt * 0.125
                    // RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
                    // RTO = RTT + 4 * RTTVar
                    long rtt = datagram.Timer.ElapsedMilliseconds;
                    long RTT = player.Rtt;
                    long RTTVar = player.RttVar;

                    player.Rtt = (long) (RTT*0.875 + rtt*0.125);
                    player.RttVar = (long) (RTTVar*0.875 + Math.Abs(RTT - rtt)*0.125);
                    player.Rto = player.Rtt + 4*player.RttVar + 10; // SYNC time in the end
                    SendDatagram(session, datagram);
                }
                else
                {
                    if (Log.IsDebugEnabled)
                        Log.DebugFormat("NAK, no datagram #{0} to resend for {1}", i, player.Username);
                }
            }
        }
Example #28
0
        internal void HandlePackage(int datagramSequenceNumber, Package message, PlayerNetworkSession playerSession)
        {
            TraceReceive(message);

            message.DatagramSequenceNumber = datagramSequenceNumber;

            if (typeof (UnknownPackage) == message.GetType())
            {
                message.PutPool();
                return;
            }

            if (typeof (McpeBatch) == message.GetType())
            {
                McpeBatch batch = (McpeBatch) message;

                var messages = new List<Package>();

                // 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));
                }
                foreach (var msg in messages)
                {
                    HandlePackage(datagramSequenceNumber, msg, playerSession);
                }

                batch.PutPool();
                return;
            }

            message.Source = "HandlePackage";

            playerSession.Player.HandlePackage(message);

            message.PutPool();
        }
Example #29
0
		internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
		{
			if (message == null) return;

			TraceReceive(message);

			if (typeof (UnknownPackage) == message.GetType())
			{
				return;
			}

			if (typeof (McpeBatch) == message.GetType())
			{
				McpeBatch batch = (McpeBatch) message;

				var messages = new List<Package>();

				// 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);
					destination.Position = 0;
					NbtBinaryReader reader = new NbtBinaryReader(destination, true);
					int len = reader.ReadInt32();
					byte[] internalBuffer = reader.ReadBytes(len);

					//byte[] internalBuffer = destination.ToArray();
					messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer));
					if (destination.Length > destination.Position) throw new Exception("Have more data");
				}
				foreach (var msg in messages)
				{
					msg.DatagramSequenceNumber = batch.DatagramSequenceNumber;
					msg.OrderingChannel = batch.OrderingChannel;
					msg.OrderingIndex = batch.OrderingIndex;
					HandlePackage(msg, playerSession);
					msg.PutPool();
				}

				return;
			}

			Player player = playerSession.Player;
			if (player != null) player.HandlePackage(message);
		}
Example #30
0
        private void DelayedProcessing(PlayerNetworkSession playerSession, ConnectedPackage package)
        {
            int datagramSequenceNumber = 0;
            lock (playerSession.ProcessSyncRoot)
            {
                datagramSequenceNumber = package._datagramSequenceNumber;

                if (datagramSequenceNumber > 0 && playerSession.LastDatagramNumber >= datagramSequenceNumber)
                {
                    Log.DebugFormat("Sequence out of order {0}", package._datagramSequenceNumber);
                }
                else if (datagramSequenceNumber > 0)
                {
                    playerSession.LastDatagramNumber = package._datagramSequenceNumber;
                }
            }
            if (ForwardAllPlayers)
            {
                playerSession.Player.SendPackage(new McpeTransfer
                {
                    endpoint = ForwardTarget
                }, true);

                return;
            }

            List<Package> messages = package.Messages;
            foreach (var message in messages)
            {
                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();
                        var fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                        HandlePackage(datagramSequenceNumber, fullMessage, playerSession);
                    }

                    continue;
                }

                message.Timer.Restart();
                HandlePackage(datagramSequenceNumber, message, playerSession);
                //message.PutPool(); // Handled in HandlePacket now()
            }
            package.PutPool();
        }
        internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            Player player = playerSession.Player;

            if (message == null)
            {
                return;
            }

            if (typeof (McpeWrapper) == message.GetType())
            {
                McpeWrapper batch = (McpeWrapper) message;

                // Get bytes
                byte[] payload = batch.payload;
                if (playerSession.CryptoContext != null && Config.GetProperty("UseEncryption", true))
                {
                    payload = CryptoUtils.Decrypt(payload, playerSession.CryptoContext);
                }

                //if (Log.IsDebugEnabled)
                //	Log.Debug($"0x{payload[0]:x2}\n{Package.HexDump(payload)}");

                var msg = PackageFactory.CreatePackage(payload[0], payload, "mcpe") ?? new UnknownPackage(payload[0], payload);
                HandlePackage(msg, playerSession);
                msg.PutPool();

                return;
            }

            if (typeof (UnknownPackage) == message.GetType())
            {
                UnknownPackage packet = (UnknownPackage) message;
                Log.Warn($"Received unknown package 0x{message.Id:X2}\n{Package.HexDump(packet.Message)}");

                return;
            }

            if (typeof (McpeBatch) == message.GetType())
            {
                Log.Debug("Handle MCPE batch message");
                McpeBatch batch = (McpeBatch) message;

                var messages = new List<Package>();

                // 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 = MiNetServer.MemoryStreamManager.GetStream();
                    defStream2.CopyTo(destination);
                    destination.Position = 0;
                    NbtBinaryReader reader = new NbtBinaryReader(destination, true);

                    while (destination.Position < destination.Length)
                    {
                        int len = reader.ReadInt32();
                        byte[] internalBuffer = reader.ReadBytes(len);

                        //if (Log.IsDebugEnabled)
                        //	Log.Debug($"0x{internalBuffer[0]:x2}\n{Package.HexDump(internalBuffer)}");

                        messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer, "mcpe") ?? new UnknownPackage(internalBuffer[0], internalBuffer));
                    }

                    if (destination.Length > destination.Position) throw new Exception("Have more data");
                }
                foreach (var msg in messages)
                {
                    msg.DatagramSequenceNumber = batch.DatagramSequenceNumber;
                    msg.OrderingChannel = batch.OrderingChannel;
                    msg.OrderingIndex = batch.OrderingIndex;
                    HandlePackage(msg, playerSession);
                    msg.PutPool();
                }

                return;
            }

            if (player != null) player.HandlePackage(message);
        }
Example #32
0
        private void HandleSplitMessage(PlayerNetworkSession playerSession, SplitPartPackage splitMessage)
        {
            int spId    = splitMessage.SplitId;
            int spIdx   = splitMessage.SplitIdx;
            int spCount = splitMessage.SplitCount;

            Int24       sequenceNumber        = splitMessage.DatagramSequenceNumber;
            Reliability reliability           = splitMessage.Reliability;
            Int24       reliableMessageNumber = splitMessage.ReliableMessageNumber;
            Int24       orderingIndex         = splitMessage.OrderingIndex;
            byte        orderingChannel       = splitMessage.OrderingChannel;

            SplitPartPackage[] spPackets;
            bool haveEmpty = false;

            // Need sync for this part since they come very fast, and very close in time.
            // If no synk, will often detect complete message two times (or more).
            lock (playerSession.Splits)
            {
                if (!playerSession.Splits.ContainsKey(spId))
                {
                    playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]);
                }

                spPackets = playerSession.Splits[spId];
                if (spPackets[spIdx] != null)
                {
                    Log.Debug("Already had splitpart (resent). Ignore this part.");
                    return;
                }
                spPackets[spIdx] = splitMessage;

                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);

                using (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 = sequenceNumber;
                        newPackage._reliability            = reliability;
                        newPackage._reliableMessageNumber  = reliableMessageNumber;
                        newPackage._orderingIndex          = orderingIndex;
                        newPackage._orderingChannel        = (byte)orderingChannel;
                        newPackage._hasSplit = false;

                        Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer, "raknet") ??
                                              new UnknownPackage(buffer[0], buffer);
                        fullMessage.DatagramSequenceNumber = sequenceNumber;
                        fullMessage.Reliability            = reliability;
                        fullMessage.ReliableMessageNumber  = reliableMessageNumber;
                        fullMessage.OrderingIndex          = orderingIndex;
                        fullMessage.OrderingChannel        = 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)}");
                        }
                        playerSession.Disconnect("Bad package received from client.", false);
                    }
                }
            }
        }
Example #33
0
        private void SendDatagram(PlayerNetworkSession session, Datagram datagram, bool updateCounter)
        {
            if (datagram.MessageParts.Count == 0)
            {
                datagram.PutPool();
                Log.WarnFormat("Failed to resend #{0}", datagram.Header.datagramSequenceNumber.IntValue());
                return;
            }

            if (updateCounter)
            {
                datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref session.DatagramSequenceNumber);
            }

            datagram.TransmissionCount++;

            byte[] data = datagram.Encode();

            datagram.Timer.Restart();

            if (!session.WaitingForAcksQueue.TryAdd(datagram.Header.datagramSequenceNumber.IntValue(), datagram))
            {
                Log.Warn(string.Format("Datagram sequence unexpectedly existed in the ACK/NAK queue already {0}", datagram.Header.datagramSequenceNumber.IntValue()));
            }

            lock (session.SyncRoot)
            {
                SendData(data, session.EndPoint, session.SyncRoot);
                int sndDelay = (int) (50f/4f);
                sndDelay = sndDelay + (20*(1/(datagram.Header.datagramSequenceNumber.IntValue() + 1)));
                //Thread.Sleep(sndDelay); // Really important to slow down speed a bit
            }
        }
Example #34
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);
            }
        }
Example #35
0
		private void EnqueueAck(PlayerNetworkSession session, int sequenceNumber)
		{
			ServerInfo.NumberOfAckSent++;
			session.PlayerAckQueue.Enqueue(sequenceNumber);
		}
Example #36
0
        /// <summary>
        ///     Processes a message.
        /// </summary>
        /// <param name="receiveBytes">The received bytes.</param>
        /// <param name="senderEndpoint">The sender's endpoint.</param>
        /// <exception cref="System.Exception">Receive ERROR, NAK in wrong place</exception>
        private void ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint)
        {
            byte msgId = receiveBytes[0];

            if (msgId == 0xFE)
            {
                Log.WarnFormat("A query detected from: {0}", senderEndpoint.Address);
                HandleQuery(receiveBytes, senderEndpoint);
            }
            else if (msgId <= (byte)DefaultMessageIdTypes.ID_USER_PACKET_ENUM)
            {
                DefaultMessageIdTypes msgIdType = (DefaultMessageIdTypes)msgId;

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

                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 = new UnconnectedPong
                    {
                        serverId   = 22345,
                        pingId     = incoming.pingId /*incoming.pingId*/,
                        serverName = string.Format(@"MCPE;{0};27;0.11.1;{1};{2}", Motd, _playerSessions.Count, 1000)
                    };
                    var data = packet.Encode();
                    TraceSend(packet);
                    SendData(data, senderEndpoint, _listener);
                    break;
                }

                case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_1:
                {
                    OpenConnectionRequest1 incoming = (OpenConnectionRequest1)message;

                    _isPerformanceTest = _isPerformanceTest || incoming.raknetProtocolVersion == byte.MaxValue;

                    var packet = new OpenConnectionReply1
                    {
                        serverGuid        = 12345,
                        mtuSize           = incoming.mtuSize,
                        serverHasSecurity = 0
                    };

                    var data = packet.Encode();
                    TraceSend(packet);
                    SendData(data, senderEndpoint, _listener);
                    break;
                }

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

                    Log.WarnFormat("New connection from: {0} {1}", senderEndpoint.Address, incoming.clientUdpPort);

                    var packet = new OpenConnectionReply2
                    {
                        serverGuid             = 12345,
                        mtuSize                = incoming.mtuSize,
                        doSecurityAndHandshake = new byte[0]
                    };

                    PlayerNetworkSession session = null;
                    lock (_playerSessions)
                    {
                        if (_playerSessions.ContainsKey(senderEndpoint))
                        {
                            PlayerNetworkSession value;
                            _playerSessions.TryRemove(senderEndpoint, out value);
                            value.Player.HandleDisconnectionNotification();
                            Log.Info("Removed ghost");
                        }

                        session = new PlayerNetworkSession(new Player(this, senderEndpoint, _levels[_random.Next(0, _levels.Count)], _pluginManager, incoming.mtuSize), senderEndpoint);
                        session.LastUpdatedTime = DateTime.UtcNow;
                        session.Mtuize          = incoming.mtuSize;

                        _playerSessions.TryAdd(senderEndpoint, session);
                    }

                    var data = packet.Encode();
                    TraceSend(packet);
                    SendData(data, senderEndpoint, session.SyncRoot);
                    break;
                }

                default:
                    Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) from {1}", msgId, senderEndpoint.Address);
                    break;
                }

                if (message != null)
                {
                    message.PutPool();
                }
                else
                {
                    Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) from {1}", msgId, senderEndpoint.Address);
                }
            }
            else
            {
                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();
                    package.Decode(receiveBytes);
                    List <Package> messages = package.Messages;

                    if (messages.Count == 1)
                    {
                        McpeBatch batch = messages.First() as McpeBatch;
                        if (batch != null)
                        {
                            messages = new List <Package>();

                            // 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));
                            }
                        }
                    }

                    // 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(senderEndpoint, package._datagramSequenceNumber);
                    }

                    PlayerNetworkSession playerSession;
                    if (_playerSessions.TryGetValue(senderEndpoint, out playerSession))
                    {
                        foreach (var message in messages)
                        {
                            if (message is 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++)
                                    {
                                        byte[] buf = spPackets[i].Message;
                                        stream.Write(buf, 0, buf.Length);
                                    }

                                    byte[] buffer      = stream.ToArray();
                                    var    fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                                    HandlePackage(fullMessage, playerSession);
                                }
                                continue;
                            }

                            message.Timer.Restart();
                            HandlePackage(message, playerSession);
                            message.PutPool();
                        }
                    }

                    package.PutPool();
                }
                else if (header.isACK && header.isValid)
                {
                    HandleAck(receiveBytes, senderEndpoint);
                }
                else if (header.isNAK && header.isValid)
                {
                    HandleNak(receiveBytes, senderEndpoint);
                }
                else if (!header.isValid)
                {
                    Log.Warn("!!!! ERROR, Invalid header !!!!!");
                }
            }
        }
Example #37
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)
                {
                    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()
            }
        }
Example #38
0
		private void SendDatagram(PlayerNetworkSession session, Datagram datagram)
		{
			if (datagram.MessageParts.Count == 0)
			{
				datagram.PutPool();
				Log.WarnFormat("Failed to resend #{0}", datagram.Header.datagramSequenceNumber.IntValue());
				return;
			}

			datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref session.DatagramSequenceNumber);

			datagram.TransmissionCount++;

			byte[] data = datagram.Encode();

			datagram.Timer.Restart();

			if (!session.WaitingForAcksQueue.TryAdd(datagram.Header.datagramSequenceNumber.IntValue(), datagram))
			{
				Log.Warn(string.Format("Datagram sequence unexpectedly existed in the ACK/NAK queue already {0}", datagram.Header.datagramSequenceNumber.IntValue()));
			}

			lock (session.SyncRoot)
			{
				SendData(data, session.EndPoint);
			}
		}
Example #39
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();
        }
Example #40
0
        private void HandleAck(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null) return;

            Player player = session.Player;
            if (player == null) return;

            Ack ack = Ack.CreateObject();
            ack.Decode(receiveBytes);

            int ackSeqNo = ack.sequenceNumber.IntValue();
            int toAckSeqNo = ack.toSequenceNumber.IntValue();
            if (ack.onlyOneSequence == 1) toAckSeqNo = ackSeqNo;

            if (ack.onlyOneSequence != 1 && ack.count > 2)
            {
                if (Log.IsDebugEnabled)
                    Log.DebugFormat("ACK from Player {0} ({5}) #{1}-{2} IsOnlyOne {3} Count={4}", player.Username, ackSeqNo, toAckSeqNo, ack.onlyOneSequence, ack.count, player.Rtt);
            }

            ack.PutPool();

            var queue = session.WaitingForAcksQueue;

            for (int i = ackSeqNo; i <= toAckSeqNo; i++)
            {
                Datagram datagram;
                if (queue.TryRemove(i, out datagram))
                {
                    // RTT = RTT * 0.875 + rtt * 0.125
                    // RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
                    // RTO = RTT + 4 * RTTVar
                    long rtt = datagram.Timer.ElapsedMilliseconds;
                    long RTT = player.Rtt;
                    long RTTVar = player.RttVar;

                    player.Rtt = (long) (RTT*0.875 + rtt*0.125);
                    player.RttVar = (long) (RTTVar*0.875 + Math.Abs(RTT - rtt)*0.125);
                    player.Rto = player.Rtt + 4*player.RttVar + 100; // SYNC time in the end

                    foreach (MessagePart part in datagram.MessageParts)
                    {
                        part.PutPool();
                    }
                    datagram.PutPool();
                }
                else
                {
                    if (Log.IsDebugEnabled)
                        Log.DebugFormat("Failed to remove ACK #{0} for {2}. Queue size={1}", i, queue.Count, player.Username);
                }
            }
        }
Example #41
0
 private void EnqueueAck(PlayerNetworkSession session, int sequenceNumber)
 {
     session.PlayerAckQueue.Enqueue(sequenceNumber);
 }
Example #42
0
        internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            if (message == null)
            {
                return;
            }

            TraceReceive(message);

            if (typeof(UnknownPackage) == message.GetType())
            {
                UnknownPackage packet = (UnknownPackage)message;
                Log.Warn($"Received unknown package 0x{message.Id:X2}\n{Package.HexDump(packet.Message)}");
                return;
            }

            if (typeof(McpeBatch) == message.GetType())
            {
                McpeBatch batch = (McpeBatch)message;

                var messages = new List <Package>();

                // 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 = MiNetServer.MemoryStreamManager.GetStream();
                    defStream2.CopyTo(destination);
                    destination.Position = 0;
                    NbtBinaryReader reader         = new NbtBinaryReader(destination, true);
                    int             len            = reader.ReadInt32();
                    byte[]          internalBuffer = reader.ReadBytes(len);

                    //byte[] internalBuffer = destination.ToArray();
                    messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer));
                    if (destination.Length > destination.Position)
                    {
                        throw new Exception("Have more data");
                    }
                }
                foreach (var msg in messages)
                {
                    msg.DatagramSequenceNumber = batch.DatagramSequenceNumber;
                    msg.OrderingChannel        = batch.OrderingChannel;
                    msg.OrderingIndex          = batch.OrderingIndex;
                    HandlePackage(msg, playerSession);
                    msg.PutPool();
                }

                return;
            }

            Player player = playerSession.Player;

            if (player != null)
            {
                player.HandlePackage(message);
            }
        }
Example #43
0
 private void SendDatagram(PlayerNetworkSession session, Datagram datagram)
 {
     SendDatagram(session, datagram, true);
 }
Example #44
0
        /// <summary>
        ///     Handles the specified package.
        /// </summary>
        /// <param name="message">The package.</param>
        /// <param name="senderEndpoint">The sender's endpoint.</param>
        private void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            TraceReceive(message);

            if (typeof (UnknownPackage) == message.GetType())
            {
                return;
            }

            if (typeof (McpeBatch) == message.GetType())
            {
                McpeBatch batch = (McpeBatch) message;

                var messages = new List<Package>();

                // 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));
                }
                foreach (var msg in messages)
                {
                    HandlePackage(msg, playerSession);
                }
            }

            playerSession.Player.HandlePackage(message);
            playerSession.LastUpdatedTime = DateTime.UtcNow;

            if (typeof (DisconnectionNotification) == message.GetType())
            {
                PlayerNetworkSession value;
                _playerSessions.TryRemove(playerSession.EndPoint, out value);
            }
        }
Example #45
0
        private void HandleNak(PlayerNetworkSession session, byte[] receiveBytes)
        {
            if (session == null)
            {
                return;
            }

            Nak nak = Nak.CreateObject();

            nak.Reset();
            nak.Decode(receiveBytes);

            var queue = session.WaitingForAcksQueue;

            foreach (Tuple <int, int> range in nak.ranges)
            {
                Interlocked.Increment(ref ServerInfo.NumberOfNakReceive);

                int start = range.Item1;
                int end   = range.Item2;

                for (int i = start; i <= end; i++)
                {
                    session.ErrorCount++;

                    // HACK: Just to make sure we aren't getting unessecary load on the queue during heavy buffering.
                    //if (ServerInfo.AvailableBytes > 1000) continue;

                    Datagram datagram;
                    //if (queue.TryRemove(i, out datagram))
                    if (!session.Evicted && queue.TryRemove(i, out datagram))
                    {
                        // RTT = RTT * 0.875 + rtt * 0.125
                        // RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
                        // RTO = RTT + 4 * RTTVar
                        long rtt    = datagram.Timer.ElapsedMilliseconds;
                        long RTT    = session.Rtt;
                        long RTTVar = session.RttVar;

                        session.Rtt    = (long)(RTT * 0.875 + rtt * 0.125);
                        session.RttVar = (long)(RTTVar * 0.875 + Math.Abs(RTT - rtt) * 0.125);
                        session.Rto    = session.Rtt + 4 * session.RttVar + 100;                    // SYNC time in the end

                        FastThreadPool.QueueUserWorkItem(delegate
                        {
                            var dgram = (Datagram)datagram;
                            if (Log.IsDebugEnabled)
                            {
                                Log.WarnFormat("NAK, resent datagram #{0} for {1}", dgram.Header.datagramSequenceNumber, session.Username);
                            }
                            SendDatagram(session, dgram);
                            Interlocked.Increment(ref ServerInfo.NumberOfResends);
                        });
                    }
                    else
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.WarnFormat("NAK, no datagram #{0} for {1}", i, session.Username);
                        }
                    }
                }
            }

            nak.PutPool();
        }
Example #46
0
        /// <summary>
        ///     Processes a message.
        /// </summary>
        /// <param name="receiveBytes">The received bytes.</param>
        /// <param name="senderEndpoint">The sender's endpoint.</param>
        /// <exception cref="System.Exception">Receive ERROR, NAK in wrong place</exception>
        private void ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint)
        {
            byte msgId = receiveBytes[0];

            if (msgId == 0xFE)
            {
                Log.WarnFormat("A query detected from: {0}", senderEndpoint.Address);
                HandleQuery(receiveBytes, senderEndpoint);
            }
            else if (msgId <= (byte) DefaultMessageIdTypes.ID_USER_PACKET_ENUM)
            {
                DefaultMessageIdTypes msgIdType = (DefaultMessageIdTypes) msgId;

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

                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 = new UnconnectedPong
                        {
                            serverId = 22345,
                            pingId = incoming.pingId /*incoming.pingId*/,
                            serverName = string.Format(@"MCPE;{0};27;0.11.1;{1};{2}", Motd, _playerSessions.Count, 1000)
                        };
                        var data = packet.Encode();
                        TraceSend(packet);
                        SendData(data, senderEndpoint, new object());
                        break;
                    }
                    case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_1:
                    {
                        OpenConnectionRequest1 incoming = (OpenConnectionRequest1) message;

                        _isPerformanceTest = _isPerformanceTest || incoming.raknetProtocolVersion == byte.MaxValue;

                        var packet = new OpenConnectionReply1
                        {
                            serverGuid = 12345,
                            mtuSize = incoming.mtuSize,
                            serverHasSecurity = 0
                        };

                        var data = packet.Encode();
                        TraceSend(packet);
                        SendData(data, senderEndpoint, new object());
                        break;
                    }
                    case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_2:
                    {
                        OpenConnectionRequest2 incoming = (OpenConnectionRequest2) message;

                        Log.WarnFormat("New connection from: {0} {1}", senderEndpoint.Address, incoming.clientUdpPort);

                        var packet = new OpenConnectionReply2
                        {
                            serverGuid = 12345,
                            mtuSize = incoming.mtuSize,
                            doSecurityAndHandshake = new byte[0]
                        };

                        PlayerNetworkSession session = null;
                        lock (_playerSessions)
                        {
                            if (_playerSessions.ContainsKey(senderEndpoint))
                            {
                                PlayerNetworkSession value;
                                _playerSessions.TryRemove(senderEndpoint, out value);
                                value.Player.HandleDisconnectionNotification();
                                Log.Info("Removed ghost");
                            }

                            Player player = PlayerFactory.CreatePlayer(this, senderEndpoint, _levels[_random.Next(0, _levels.Count)], incoming.mtuSize);
                            session = new PlayerNetworkSession(player, senderEndpoint);
                            session.LastUpdatedTime = DateTime.UtcNow;
                            session.Mtuize = incoming.mtuSize;

                            _playerSessions.TryAdd(senderEndpoint, session);
                        }

                        var data = packet.Encode();
                        TraceSend(packet);
                        SendData(data, senderEndpoint, session.SyncRoot);
                        break;
                    }
                    default:
                        Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) from {1}", msgId, senderEndpoint.Address);
                        break;
                }

                if (message != null)
                {
                    message.PutPool();
                }
                else
                {
                    Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) from {1}", msgId, senderEndpoint.Address);
                }
            }
            else
            {
                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();
                    package.Decode(receiveBytes);
                    List<Package> messages = package.Messages;

                    if (messages.Count == 1)
                    {
                        McpeBatch batch = messages.First() as McpeBatch;
                        if (batch != null)
                        {
                            messages = new List<Package>();

                            // 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));
                            }
                        }
                    }

                    // 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(senderEndpoint, package._datagramSequenceNumber);
                    }

                    PlayerNetworkSession playerSession;
                    if (_playerSessions.TryGetValue(senderEndpoint, out playerSession))
                    {
                        foreach (var message in messages)
                        {
                            if (message is 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++)
                                    {
                                        byte[] buf = spPackets[i].Message;
                                        stream.Write(buf, 0, buf.Length);
                                    }

                                    byte[] buffer = stream.ToArray();
                                    var fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                                    HandlePackage(fullMessage, playerSession);
                                }
                                continue;
                            }

                            message.Timer.Restart();
                            HandlePackage(message, playerSession);
                            message.PutPool();
                        }
                    }

                    package.PutPool();
                }
                else if (header.isACK && header.isValid)
                {
                    HandleAck(receiveBytes, senderEndpoint);
                }
                else if (header.isNAK && header.isValid)
                {
                    HandleNak(receiveBytes, senderEndpoint);
                }
                else if (!header.isValid)
                {
                    Log.Warn("!!!! ERROR, Invalid header !!!!!");
                }
            }
        }
Example #47
0
        internal void HandlePackage(Package message, PlayerNetworkSession playerSession)
        {
            //SignalTick();

            try
            {
                if (message == null)
                {
                    return;
                }

                if (typeof(UnknownPackage) == message.GetType())
                {
                    UnknownPackage packet = (UnknownPackage)message;
                    if (Log.IsDebugEnabled)
                    {
                        Log.Warn($"Received unknown package 0x{message.Id:X2}\n{Package.HexDump(packet.Message)}");
                    }

                    message.PutPool();
                    return;
                }

                if (typeof(McpeWrapper) == message.GetType())
                {
                    McpeWrapper batch    = (McpeWrapper)message;
                    var         messages = new List <Package>();

                    // Get bytes
                    byte[] payload = batch.payload;
                    if (playerSession.CryptoContext != null && playerSession.CryptoContext.UseEncryption)
                    {
                        throw new Exception("No crypto enabled");
                    }

                    // 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
                        using (MemoryStream destination = MiNetServer.MemoryStreamManager.GetStream())
                        {
                            defStream2.CopyTo(destination);
                            destination.Position = 0;
                            NbtBinaryReader reader = new NbtBinaryReader(destination, true);

                            while (destination.Position < destination.Length)
                            {
                                //int len = reader.ReadInt32();
                                int    len            = BatchUtils.ReadLength(destination);
                                byte[] internalBuffer = reader.ReadBytes(len);

                                //if (Log.IsDebugEnabled)
                                //	Log.Debug($"0x{internalBuffer[0]:x2}\n{Package.HexDump(internalBuffer)}");

                                messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer, "mcpe") ??
                                             new UnknownPackage(internalBuffer[0], internalBuffer));
                            }

                            if (destination.Length > destination.Position)
                            {
                                throw new Exception("Have more data");
                            }
                        }
                    }
                    foreach (var msg in messages)
                    {
                        // Temp fix for performance, take 1.
                        var interact = msg as McpeInteract;
                        if (interact?.actionId == 4 && interact.targetRuntimeEntityId == 0)
                        {
                            continue;
                        }

                        msg.DatagramSequenceNumber = batch.DatagramSequenceNumber;
                        msg.Reliability            = batch.Reliability;
                        msg.ReliableMessageNumber  = batch.ReliableMessageNumber;
                        msg.OrderingChannel        = batch.OrderingChannel;
                        msg.OrderingIndex          = batch.OrderingIndex;
                        HandlePackage(msg, playerSession);
                    }

                    message.PutPool();
                    return;
                }

                MiNetServer.TraceReceive(message);

                if (CryptoContext != null && CryptoContext.UseEncryption)
                {
                    MiNetServer.FastThreadPool.QueueUserWorkItem(delegate()
                    {
                        HandlePackage(MessageHandler, message as Package);
                        message.PutPool();
                    });
                }
                else
                {
                    HandlePackage(MessageHandler, message);
                    message.PutPool();
                }
            }
            catch (Exception e)
            {
                Log.Error("Package handling", e);
                throw;
            }
        }
Example #48
0
        internal void HandlePacket(Packet message, PlayerNetworkSession playerSession)
        {
            //SignalTick();

            try
            {
                if (message == null)
                {
                    return;
                }

                if (typeof(UnknownPacket) == message.GetType())
                {
                    UnknownPacket packet = (UnknownPacket)message;
                    if (Log.IsDebugEnabled)
                    {
                        Log.Warn($"Received unknown packet 0x{message.Id:X2}\n{Packet.HexDump(packet.Message)}");
                    }

                    message.PutPool();
                    return;
                }

                if (typeof(McpeWrapper) == message.GetType())
                {
                    McpeWrapper batch    = (McpeWrapper)message;
                    var         messages = new List <Packet>();

                    // Get bytes
                    byte[] payload = batch.payload;
                    if (playerSession.CryptoContext != null && playerSession.CryptoContext.UseEncryption)
                    {
                        payload = CryptoUtils.Decrypt(payload, playerSession.CryptoContext);
                    }


                    // Decompress bytes

                    MemoryStream stream = new MemoryStream(payload);
                    if (stream.ReadByte() != 0x78)
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.Error($"Incorrect ZLib header. Expected 0x78 0x9C 0x{message.Id:X2}\n{Packet.HexDump(batch.payload)}");
                        }
                        if (Log.IsDebugEnabled)
                        {
                            Log.Error($"Incorrect ZLib header. Decrypted 0x{message.Id:X2}\n{Packet.HexDump(payload)}");
                        }
                        throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C");
                    }
                    stream.ReadByte();
                    using (var deflateStream = new DeflateStream(stream, CompressionMode.Decompress, false))
                    {
                        // Get actual packet out of bytes
                        using (MemoryStream destination = MiNetServer.MemoryStreamManager.GetStream())
                        {
                            deflateStream.CopyTo(destination);
                            destination.Position = 0;

                            while (destination.Position < destination.Length)
                            {
                                int  len = (int)VarInt.ReadUInt32(destination);
                                long pos = destination.Position;
                                int  id  = (int)VarInt.ReadUInt32(destination);
                                len = (int)(len - (destination.Position - pos));                                  // calculate len of buffer after varint
                                byte[] internalBuffer = new byte[len];
                                destination.Read(internalBuffer, 0, len);

                                //if (Log.IsDebugEnabled)
                                //	Log.Debug($"0x{internalBuffer[0]:x2}\n{Packet.HexDump(internalBuffer)}");

                                try
                                {
                                    messages.Add(PacketFactory.Create((byte)id, internalBuffer, "mcpe") ??
                                                 new UnknownPacket((byte)id, internalBuffer));
                                }
                                catch (Exception e)
                                {
                                    if (Log.IsDebugEnabled)
                                    {
                                        Log.Warn($"Error parsing packet 0x{message.Id:X2}\n{Packet.HexDump(internalBuffer)}");
                                    }

                                    throw;
                                }
                            }

                            if (destination.Length > destination.Position)
                            {
                                throw new Exception("Have more data");
                            }
                        }
                    }
                    foreach (var msg in messages)
                    {
                        // Temp fix for performance, take 1.
                        var interact = msg as McpeInteract;
                        if (interact?.actionId == 4 && interact.targetRuntimeEntityId == 0)
                        {
                            continue;
                        }

                        msg.DatagramSequenceNumber = batch.DatagramSequenceNumber;
                        msg.Reliability            = batch.Reliability;
                        msg.ReliableMessageNumber  = batch.ReliableMessageNumber;
                        msg.OrderingChannel        = batch.OrderingChannel;
                        msg.OrderingIndex          = batch.OrderingIndex;
                        HandlePacket(msg, playerSession);
                    }

                    message.PutPool();
                    return;
                }

                MiNetServer.TraceReceive(message);

                if (CryptoContext != null && CryptoContext.UseEncryption)
                {
                    MiNetServer.FastThreadPool.QueueUserWorkItem(() =>
                    {
                        HandlePacket(MessageHandler, message as Packet);
                        message.PutPool();
                    });
                }
                else
                {
                    HandlePacket(MessageHandler, message);
                    message.PutPool();
                }
            }
            catch (Exception e)
            {
                Log.Error("Packet handling", e);
                throw;
            }
        }
Example #49
0
 public LoginMessageHandler(PlayerNetworkSession session)
 {
     _session = session;
 }
Example #50
0
 public LoginMessageHandler(PlayerNetworkSession session)
 {
     _session = session;
 }