From 53b8c2328e9b6427bcd94a7140c7d12e3fd8dfd3 Mon Sep 17 00:00:00 2001 From: KennyTV Date: Thu, 23 Apr 2020 20:17:09 +0200 Subject: [PATCH] Uncache UserConnection on channel close, fix memory leak --- .../multiversion/PlayerSneakListener.java | 2 +- .../bukkit/platform/BukkitViaLoader.java | 9 -- .../us/myles/ViaVersion/BungeePlugin.java | 27 ++-- .../ViaVersion/api/data/UserConnection.java | 124 ++++++++++++++++-- .../api/platform/ViaConnectionManager.java | 3 + .../protocols/base/ProtocolInfo.java | 11 ++ .../sponge/listeners/ClientLeaveListener.java | 12 -- .../sponge/platform/SpongeViaLoader.java | 3 - .../us/myles/ViaVersion/VelocityPlugin.java | 23 ++-- 9 files changed, 147 insertions(+), 67 deletions(-) delete mode 100644 sponge/src/main/java/us/myles/ViaVersion/sponge/listeners/ClientLeaveListener.java diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java index b1172b884..45a66eb9a 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java @@ -27,7 +27,7 @@ public class PlayerSneakListener extends ViaBukkitListener { private final boolean is1_14Fix; private Map sneaking; // true = 1.14+, else false private Set sneakingUuids; - private Method getHandle; + private final Method getHandle; private Method setSize; private boolean useCache; diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java index 52cb7a638..7c80e7652 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java @@ -2,10 +2,8 @@ package us.myles.ViaVersion.bukkit.platform; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.scheduler.BukkitTask; import us.myles.ViaVersion.ViaVersionPlugin; import us.myles.ViaVersion.api.Via; @@ -73,13 +71,6 @@ public class BukkitViaLoader implements ViaPlatformLoader { // Add ProtocolSupport ConnectListener if necessary. ClassGenerator.registerPSConnectListener(plugin); - registerListener(new Listener() { - @EventHandler - public void onPlayerQuit(PlayerQuitEvent e) { - Via.getManager().handleDisconnect(e.getPlayer().getUniqueId()); - } - }); - /* 1.9 client to 1.8 server */ if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) { storeListener(new ArmorListener(plugin)).register(); diff --git a/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java b/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java index 2522d191c..55ed1227e 100644 --- a/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java +++ b/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java @@ -2,31 +2,34 @@ package us.myles.ViaVersion; import com.google.gson.JsonObject; import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.protocol.ProtocolConstants; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.ViaAPI; import us.myles.ViaVersion.api.command.ViaCommandSender; import us.myles.ViaVersion.api.configuration.ConfigurationProvider; import us.myles.ViaVersion.api.data.MappingDataLoader; -import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.platform.TaskId; import us.myles.ViaVersion.api.platform.ViaConnectionManager; import us.myles.ViaVersion.api.platform.ViaPlatform; import us.myles.ViaVersion.bungee.commands.BungeeCommand; import us.myles.ViaVersion.bungee.commands.BungeeCommandHandler; import us.myles.ViaVersion.bungee.commands.BungeeCommandSender; -import us.myles.ViaVersion.bungee.platform.*; +import us.myles.ViaVersion.bungee.platform.BungeeTaskId; +import us.myles.ViaVersion.bungee.platform.BungeeViaAPI; +import us.myles.ViaVersion.bungee.platform.BungeeViaConfig; +import us.myles.ViaVersion.bungee.platform.BungeeViaInjector; +import us.myles.ViaVersion.bungee.platform.BungeeViaLoader; import us.myles.ViaVersion.bungee.service.ProtocolDetectorService; import us.myles.ViaVersion.dump.PluginInfo; import us.myles.ViaVersion.util.GsonUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; import java.util.concurrent.TimeUnit; public class BungeePlugin extends Plugin implements ViaPlatform, Listener { @@ -193,16 +196,4 @@ public class BungeePlugin extends Plugin implements ViaPlatform, public ViaConnectionManager getConnectionManager() { return connectionManager; } - - @EventHandler - public void onQuit(PlayerDisconnectEvent e) { - UserConnection userConnection = getConnectionManager().getConnectedClient(e.getPlayer().getUniqueId()); - if (userConnection != null) { - // Only remove if the connection is disconnected (eg. relogin) - if (userConnection.getChannel() == null || !userConnection.getChannel().isOpen()) { - Via.getManager().handleDisconnect(e.getPlayer().getUniqueId()); - } - } - - } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java b/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java index dab0fc13c..0221bd197 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java +++ b/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java @@ -5,7 +5,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import lombok.Data; import net.md_5.bungee.api.ChatColor; import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.Via; @@ -17,23 +16,25 @@ import us.myles.ViaVersion.util.PipelineUtil; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; -@Data public class UserConnection { + private static final AtomicLong IDS = new AtomicLong(); + private final long id = IDS.incrementAndGet(); private final Channel channel; Map storedObjects = new ConcurrentHashMap<>(); private boolean active = true; - private boolean pendingDisconnect = false; + private boolean pendingDisconnect; private Object lastPacket; - private long sentPackets = 0L; - private long receivedPackets = 0L; + private long sentPackets; + private long receivedPackets; // Used for tracking pps - private long startTime = 0L; - private long intervalPackets = 0L; + private long startTime; + private long intervalPackets; private long packetsPerSecond = -1L; // Used for handling warnings (over time) - private int secondsObserved = 0; - private int warnings = 0; + private int secondsObserved; + private int warnings; public UserConnection(Channel channel) { this.channel = channel; @@ -242,4 +243,109 @@ public class UserConnection { public void sendRawPacketToServer(ByteBuf packet) { sendRawPacketToServer(packet, false); } + + public long getId() { + return id; + } + + public Channel getChannel() { + return channel; + } + + public Map getStoredObjects() { + return storedObjects; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public boolean isPendingDisconnect() { + return pendingDisconnect; + } + + public void setPendingDisconnect(boolean pendingDisconnect) { + this.pendingDisconnect = pendingDisconnect; + } + + public Object getLastPacket() { + return lastPacket; + } + + public void setLastPacket(Object lastPacket) { + this.lastPacket = lastPacket; + } + + public long getSentPackets() { + return sentPackets; + } + + public void setSentPackets(long sentPackets) { + this.sentPackets = sentPackets; + } + + public long getReceivedPackets() { + return receivedPackets; + } + + public void setReceivedPackets(long receivedPackets) { + this.receivedPackets = receivedPackets; + } + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public long getIntervalPackets() { + return intervalPackets; + } + + public void setIntervalPackets(long intervalPackets) { + this.intervalPackets = intervalPackets; + } + + public long getPacketsPerSecond() { + return packetsPerSecond; + } + + public void setPacketsPerSecond(long packetsPerSecond) { + this.packetsPerSecond = packetsPerSecond; + } + + public int getSecondsObserved() { + return secondsObserved; + } + + public void setSecondsObserved(int secondsObserved) { + this.secondsObserved = secondsObserved; + } + + public int getWarnings() { + return warnings; + } + + public void setWarnings(int warnings) { + this.warnings = warnings; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UserConnection that = (UserConnection) o; + return id == that.id; + } + + @Override + public int hashCode() { + return Long.hashCode(id); + } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java b/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java index cb7ea10fe..77ac1b6e1 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java +++ b/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java @@ -1,5 +1,6 @@ package us.myles.ViaVersion.api.platform; +import io.netty.channel.ChannelFutureListener; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.protocols.base.ProtocolInfo; @@ -18,6 +19,8 @@ public class ViaConnectionManager { UUID id = connection.get(ProtocolInfo.class).getUuid(); connections.add(connection); clients.put(id, connection); + + connection.getChannel().closeFuture().addListener((ChannelFutureListener) future -> onDisconnect(connection)); } public void onDisconnect(UserConnection connection) { diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/base/ProtocolInfo.java b/common/src/main/java/us/myles/ViaVersion/protocols/base/ProtocolInfo.java index 565eab34b..a2827538c 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/base/ProtocolInfo.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/base/ProtocolInfo.java @@ -66,4 +66,15 @@ public class ProtocolInfo extends StoredObject { public void setPipeline(ProtocolPipeline pipeline) { this.pipeline = pipeline; } + + @Override + public String toString() { + return "ProtocolInfo{" + + "state=" + state + + ", protocolVersion=" + protocolVersion + + ", serverProtocolVersion=" + serverProtocolVersion + + ", username='" + username + '\'' + + ", uuid=" + uuid + + '}'; + } } diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/listeners/ClientLeaveListener.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/listeners/ClientLeaveListener.java deleted file mode 100644 index 874ab3429..000000000 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/listeners/ClientLeaveListener.java +++ /dev/null @@ -1,12 +0,0 @@ -package us.myles.ViaVersion.sponge.listeners; - -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.network.ClientConnectionEvent; -import us.myles.ViaVersion.api.Via; - -public class ClientLeaveListener { - @Listener - public void onDisconnect(ClientConnectionEvent.Disconnect disconnect) { - Via.getManager().handleDisconnect(disconnect.getTargetEntity().getUniqueId()); - } -} diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java index cc8ecfe1d..e73a8b7df 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java @@ -13,7 +13,6 @@ import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; -import us.myles.ViaVersion.sponge.listeners.ClientLeaveListener; import us.myles.ViaVersion.sponge.listeners.UpdateListener; import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.BlockListener; import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.DeathListener; @@ -50,8 +49,6 @@ public class SpongeViaLoader implements ViaPlatformLoader { public void load() { // Update Listener registerListener(new UpdateListener()); - /* Base Protocol */ - registerListener(new ClientLeaveListener()); /* 1.9 client to 1.8 server */ if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) { diff --git a/velocity/src/main/java/us/myles/ViaVersion/VelocityPlugin.java b/velocity/src/main/java/us/myles/ViaVersion/VelocityPlugin.java index 1637eecd1..70bbd800f 100644 --- a/velocity/src/main/java/us/myles/ViaVersion/VelocityPlugin.java +++ b/velocity/src/main/java/us/myles/ViaVersion/VelocityPlugin.java @@ -3,7 +3,6 @@ package us.myles.ViaVersion; import com.google.gson.JsonObject; import com.google.inject.Inject; import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.PluginContainer; @@ -18,7 +17,6 @@ import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.command.ViaCommandSender; import us.myles.ViaVersion.api.configuration.ConfigurationProvider; import us.myles.ViaVersion.api.data.MappingDataLoader; -import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.platform.TaskId; import us.myles.ViaVersion.api.platform.ViaConnectionManager; import us.myles.ViaVersion.api.platform.ViaPlatform; @@ -27,13 +25,19 @@ import us.myles.ViaVersion.util.GsonUtil; import us.myles.ViaVersion.velocity.VersionInfo; import us.myles.ViaVersion.velocity.command.VelocityCommandHandler; import us.myles.ViaVersion.velocity.command.VelocityCommandSender; -import us.myles.ViaVersion.velocity.platform.*; +import us.myles.ViaVersion.velocity.platform.VelocityTaskId; +import us.myles.ViaVersion.velocity.platform.VelocityViaAPI; +import us.myles.ViaVersion.velocity.platform.VelocityViaConfig; +import us.myles.ViaVersion.velocity.platform.VelocityViaInjector; +import us.myles.ViaVersion.velocity.platform.VelocityViaLoader; import us.myles.ViaVersion.velocity.service.ProtocolDetectorService; import us.myles.ViaVersion.velocity.util.LoggerWrapper; import java.io.File; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import java.util.concurrent.TimeUnit; @Plugin( @@ -82,17 +86,6 @@ public class VelocityPlugin implements ViaPlatform { Via.getManager().init(); } - @Subscribe - public void onQuit(DisconnectEvent e) { - UserConnection userConnection = connectionManager.getConnectedClient(e.getPlayer().getUniqueId()); - if (userConnection != null) { - // Only remove if the connection is disconnected (eg. relogin) - if (userConnection.getChannel() == null || !userConnection.getChannel().isOpen()) { - Via.getManager().handleDisconnect(e.getPlayer().getUniqueId()); - } - } - } - @Override public String getPlatformName() { String proxyImpl = ProxyServer.class.getPackage().getImplementationTitle();