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); Player oldPlayer = session.Player; oldPlayer?.Disconnect("Reconnecting.", false); _playerSessions.TryRemove(senderEndpoint, out session); } session = new PlayerNetworkSession(null, senderEndpoint, incoming.mtuSize) { State = ConnectionState.Connecting, LastUpdatedTime = DateTime.UtcNow, Mtuize = incoming.mtuSize }; _playerSessions.TryAdd(senderEndpoint, session); } Player player = PlayerFactory.CreatePlayer(this, senderEndpoint); player.ClientGuid = incoming.clientGuid; player.NetworkSession = session; session.Player = player; var reply = OpenConnectionReply2.CreateObject(); reply.serverGuid = 12345; reply.clientendpoint = senderEndpoint; reply.mtuSize = incoming.mtuSize; reply.doSecurityAndHandshake = new byte[1]; var data = reply.Encode(); reply.PutPool(); TraceSend(reply); SendData(data, senderEndpoint); }
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."); } } }
public void Kick(Player player, string otherUser) { player.Level.BroadcastMessage(string.Format(ChatColors.Gold + "{0} tried to kick {1} but kicked self instead!!", player.Username, otherUser), type: MessageType.Raw); player.Disconnect("You kicked yourself :-)"); }
public void Ban(Player player, string otherUser) { player.Level.BroadcastMessage(string.Format(ChatColors.Gold + "{0} tried to ban {1} but banned self instead!!", player.Username, otherUser), type: MessageType.Raw); player.Disconnect("Oopps, banned the wrong player. See ya soon!!"); }
private void ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint) { byte msgId = receiveBytes[0]; if (msgId == 0xFE) { Log.InfoFormat("A query detected from: {0}", senderEndpoint.Address); HandleQuery(receiveBytes, senderEndpoint); } else if (msgId <= (byte)DefaultMessageIdTypes.ID_USER_PACKET_ENUM) { HandleRakNetMessage(receiveBytes, senderEndpoint, msgId); } else { PlayerNetworkSession playerSession; if (!_playerSessions.TryGetValue(senderEndpoint, out playerSession)) { //Log.DebugFormat("Receive MCPE message 0x{1:x2} without session {0}", senderEndpoint.Address, msgId); //if (!_badPacketBans.ContainsKey(senderEndpoint.Address)) //{ // _badPacketBans.Add(senderEndpoint.Address, true); //} return; } Player player = playerSession.Player; if (player == null) { Log.ErrorFormat("Receive MCPE message 0x{1:x2} without player {0}. Session removed.", senderEndpoint.Address, msgId); _playerSessions.TryRemove(senderEndpoint, out playerSession); //if (!_badPacketBans.ContainsKey(senderEndpoint.Address)) //{ // _badPacketBans.Add(senderEndpoint.Address, true); //} return; } if (playerSession.Evicted) { return; } playerSession.LastUpdatedTime = DateTime.UtcNow; DatagramHeader header = new DatagramHeader(receiveBytes[0]); if (!header.isACK && !header.isNAK && header.isValid) { if (receiveBytes[0] == 0xa0) { throw new Exception("Receive ERROR, NAK in wrong place"); } ConnectedPackage package = ConnectedPackage.CreateObject(); try { package.Decode(receiveBytes); } catch (Exception e) { player.Disconnect("Bad package received from client."); //if (Log.IsDebugEnabled) { Log.Warn("Bad packet " + receiveBytes[0], e); } GreylistManager.Blacklist(senderEndpoint.Address); return; } // IF reliable code below is enabled, useItem start sending doubles // for some unknown reason. //Reliability reliability = package._reliability; //if (reliability == Reliability.Reliable // || reliability == Reliability.ReliableSequenced // || reliability == Reliability.ReliableOrdered // ) { EnqueueAck(playerSession, package._datagramSequenceNumber); } DelayedProcessing(playerSession, package); package.PutPool(); } else if (header.isACK && header.isValid) { HandleAck(playerSession, receiveBytes); } else if (header.isNAK && header.isValid) { HandleNak(playerSession, receiveBytes); } else if (!header.isValid) { Log.Warn("!!!! ERROR, Invalid header !!!!!"); } } }
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 DelayedProcessing(PlayerNetworkSession playerSession, ConnectedPackage package) { Player player = playerSession.Player; if (ForwardAllPlayers) { player.SendPackage(new McpeTransfer { endpoint = ForwardTarget }, true); return; } List <Package> messages = package.Messages; foreach (var message in messages) { message.DatagramSequenceNumber = package._datagramSequenceNumber; message.OrderingChannel = package._orderingChannel; message.OrderingIndex = package._orderingIndex; if (message is SplitPartPackage) { message.Source = "Receive SplitPartPackage"; SplitPartPackage splitMessage = message as SplitPartPackage; int spId = package._splitPacketId; int spIdx = package._splitPacketIndex; int spCount = package._splitPacketCount; if (!playerSession.Splits.ContainsKey(spId)) { playerSession.Splits.Add(spId, new SplitPartPackage[spCount]); } SplitPartPackage[] spPackets = playerSession.Splits[spId]; spPackets[spIdx] = splitMessage; bool haveEmpty = false; for (int i = 0; i < spPackets.Length; i++) { haveEmpty = haveEmpty || spPackets[i] == null; } if (!haveEmpty) { Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId); MemoryStream stream = new MemoryStream(); for (int i = 0; i < spPackets.Length; i++) { SplitPartPackage splitPartPackage = spPackets[i]; byte[] buf = splitPartPackage.Message; stream.Write(buf, 0, buf.Length); splitPartPackage.PutPool(); } playerSession.Splits.Remove(spId); byte[] buffer = stream.ToArray(); try { Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer); fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber; fullMessage.OrderingChannel = package._orderingChannel; fullMessage.OrderingIndex = package._orderingIndex; HandlePackage(fullMessage, playerSession); fullMessage.PutPool(); } catch (Exception e) { player.Disconnect("Bad package received from client."); } } continue; } message.Timer.Restart(); HandlePackage(message, playerSession); message.PutPool(); // Handled in HandlePacket now() } }
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 ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint) { byte msgId = receiveBytes[0]; if (msgId == 0xFE) { Log.InfoFormat("A query detected from: {0}", senderEndpoint.Address); HandleQuery(receiveBytes, senderEndpoint); } else if (msgId <= (byte)DefaultMessageIdTypes.ID_USER_PACKET_ENUM) { HandleRakNetMessage(receiveBytes, senderEndpoint, msgId); } else { PlayerNetworkSession playerSession; if (!_playerSessions.TryGetValue(senderEndpoint, out playerSession)) { Log.DebugFormat("Receive MCPE message 0x{1:x2} without session {0}", senderEndpoint.Address, msgId); return; } Player player = playerSession.Player; if (player == null) { Log.ErrorFormat("Receive MCPE message 0x{1:x2} without player {0}. Session removed.", senderEndpoint.Address, msgId); _playerSessions.TryRemove(senderEndpoint, out playerSession); return; } if (playerSession.Evicted) { return; } playerSession.LastUpdatedTime = DateTime.UtcNow; DatagramHeader header = new DatagramHeader(receiveBytes[0]); if (!header.isACK && !header.isNAK && header.isValid) { if (receiveBytes[0] == 0xa0) { throw new Exception("Receive ERROR, NAK in wrong place"); } ConnectedPackage package = ConnectedPackage.CreateObject(); try { package.Decode(receiveBytes); } catch (Exception e) { player.Disconnect("Bad package received from client."); return; } // IF reliable code below is enabled, useItem start sending doubles // for some unknown reason. //Reliability reliability = package._reliability; //if (reliability == Reliability.Reliable // || reliability == Reliability.ReliableSequenced // || reliability == Reliability.ReliableOrdered // ) { EnqueueAck(playerSession, package._datagramSequenceNumber); } List <Package> messages = package.Messages; if (messages.Count == 1) { McpeBatch batch = messages.First() as McpeBatch; if (batch != null) { batch.Source = "Client"; messages.Clear(); // Get bytes byte[] payload = batch.payload; // Decompress bytes MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { // Get actual package out of bytes MemoryStream destination = new MemoryStream(); defStream2.CopyTo(destination); byte[] internalBuffer = destination.ToArray(); messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer)); } batch.PutPool(); } } DelayedProcessing(playerSession, package); package.PutPool(); } else if (header.isACK && header.isValid) { ServerInfo.NumberOfAckReceive++; HandleAck(playerSession, receiveBytes); } else if (header.isNAK && header.isValid) { ServerInfo.NumberOfNakReceive++; HandleNak(playerSession, receiveBytes); } else if (!header.isValid) { Log.Warn("!!!! ERROR, Invalid header !!!!!"); } } }
private void Update(object state) { if (!Monitor.TryEnter(_updateGlobalLock)) { return; } try { long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond; Parallel.ForEach(_playerSessions.Values.ToArray(), delegate(PlayerNetworkSession session) { if (session == null) { return; } if (session.Evicted) { return; } try { Player player = session.Player; long lastUpdate = session.LastUpdatedTime.Ticks / TimeSpan.TicksPerMillisecond; if (lastUpdate + InacvitityTimeout + 3000 + Math.Min(5000, ServerInfo.AvailableBytes) < now) { session.Evicted = true; // Disconnect user ThreadPool.QueueUserWorkItem(delegate(object o) { PlayerNetworkSession s = o as PlayerNetworkSession; if (s != null) { Player p = s.Player; if (p != null) { p.Disconnect("You've been kicked with reason: Network timeout."); } else { if (ServerInfo.PlayerSessions.TryRemove(session.EndPoint, out session)) { session.Player = null; session.State = ConnectionState.Unconnected; session.Evicted = true; session.Clean(); } } } }, session); return; } if (session.State != ConnectionState.Connected && player != null && lastUpdate + 3000 < now) { ThreadPool.QueueUserWorkItem(delegate(object o) { PlayerNetworkSession s = o as PlayerNetworkSession; if (s != null) { Player p = s.Player; if (p != null) { p.Disconnect("You've been kicked with reason: Lost connection."); } } }, session); return; } if (player == null) { return; } if (lastUpdate + InacvitityTimeout < now) { player.DetectLostConnection(); } long rto = Math.Max(100, player.Rto); var queue = session.WaitingForAcksQueue; foreach (var datagram in queue.Values) { if (!datagram.Timer.IsRunning) { Log.ErrorFormat("Timer not running for #{0}", datagram.Header.datagramSequenceNumber); datagram.Timer.Restart(); continue; } if (player.Rtt == -1) { continue; } long elapsedTime = datagram.Timer.ElapsedMilliseconds; if (elapsedTime >= rto * (datagram.TransmissionCount + 2)) { Datagram deleted; if (queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted)) { session.ErrorCount++; if (deleted.TransmissionCount > 1) { Log.DebugFormat("Remove from ACK queue #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTT {5}", deleted.Header.datagramSequenceNumber.IntValue(), player.Username, deleted.FirstMessageId, elapsedTime, rto, player.Rtt); foreach (MessagePart part in deleted.MessageParts) { part.PutPool(); } deleted.PutPool(); continue; } if (!session.Evicted) { ThreadPool.QueueUserWorkItem(delegate(object data) { try { Log.DebugFormat("Resent #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTT {5}", deleted.Header.datagramSequenceNumber.IntValue(), player.Username, deleted.FirstMessageId, elapsedTime, rto, player.Rtt); SendDatagram(session, (Datagram)data); } catch (Exception e) { } }, datagram); } } } } } catch (Exception e) { } }); } finally { Monitor.Exit(_updateGlobalLock); } }
private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage, Player player) { int spId = package._splitPacketId; int spIdx = package._splitPacketIndex; int spCount = package._splitPacketCount; if (!playerSession.Splits.ContainsKey(spId)) { playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]); } SplitPartPackage[] spPackets = playerSession.Splits[spId]; spPackets[spIdx] = splitMessage; bool haveEmpty = false; for (int i = 0; i < spPackets.Length; i++) { haveEmpty = haveEmpty || spPackets[i] == null; } if (!haveEmpty) { Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId); SplitPartPackage[] waste; playerSession.Splits.TryRemove(spId, out waste); MemoryStream stream = MemoryStreamManager.GetStream(); for (int i = 0; i < spPackets.Length; i++) { SplitPartPackage splitPartPackage = spPackets[i]; byte[] buf = splitPartPackage.Message; if (buf == null) { Log.Error("Expected bytes in splitpart, but got none"); continue; } stream.Write(buf, 0, buf.Length); splitPartPackage.PutPool(); } byte[] buffer = stream.ToArray(); try { ConnectedPackage newPackage = ConnectedPackage.CreateObject(); newPackage._datagramSequenceNumber = package._datagramSequenceNumber; newPackage._reliability = package._reliability; newPackage._reliableMessageNumber = package._reliableMessageNumber; newPackage._sequencingIndex = package._sequencingIndex; newPackage._orderingIndex = package._orderingIndex; newPackage._orderingChannel = package._orderingChannel; newPackage._hasSplit = false; Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer, "raknet") ?? new UnknownPackage(buffer[0], buffer); fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber; fullMessage.Reliability = package._reliability; fullMessage.ReliableMessageNumber = package._reliableMessageNumber; fullMessage.OrderingIndex = package._orderingIndex; fullMessage.OrderingChannel = package._orderingChannel; newPackage.Messages = new List <Package>(); newPackage.Messages.Add(fullMessage); Log.Debug($"Assembled split package {newPackage._reliability} message #{newPackage._reliableMessageNumber}, Chan: #{newPackage._orderingChannel}, OrdIdx: #{newPackage._orderingIndex}"); HandleConnectedPackage(playerSession, newPackage); newPackage.PutPool(); } catch (Exception e) { Log.Error("Error during split message parsing", e); if (Log.IsDebugEnabled) { Log.Debug($"0x{buffer[0]:x2}\n{Package.HexDump(buffer)}"); } player.Disconnect("Bad package received from client."); } } }