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."); } } }
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); }
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); } }
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(); }
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(); }
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); } }
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() } }
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); } }
public void SendPackage(PlayerNetworkSession session, Package message) { foreach (var datagram in Datagram.CreateDatagrams(message, session.MtuSize, session)) { SendDatagram(session, datagram); } message.PutPool(); }
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; }
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); } } }
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(); }
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 }
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); } }
/// <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); } }
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; }
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); } }
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); } }
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); } }
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(); }
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); }
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; }
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(); }
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."); } } }
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() } }
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); }
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); } } }
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(); }
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); }
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); }
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); } } } }
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 } }
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); } }
private void EnqueueAck(PlayerNetworkSession session, int sequenceNumber) { ServerInfo.NumberOfAckSent++; session.PlayerAckQueue.Enqueue(sequenceNumber); }
/// <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 !!!!!"); } } }
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() } }
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); } }
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(); }
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); } } }
private void EnqueueAck(PlayerNetworkSession session, int sequenceNumber) { session.PlayerAckQueue.Enqueue(sequenceNumber); }
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); } }
private void SendDatagram(PlayerNetworkSession session, Datagram datagram) { SendDatagram(session, datagram, true); }
/// <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); } }
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(); }
/// <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 !!!!!"); } } }
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; } }
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; } }
public LoginMessageHandler(PlayerNetworkSession session) { _session = session; }