diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 893fa00b..834730c7 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -31,6 +31,8 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; import java.util.logging.Logger; import lombok.Getter; @@ -98,7 +100,8 @@ public class BungeeCord extends ProxyServer /** * Fully qualified connections. */ - public TMap connections = new CaseInsensitiveMap<>(); + private final TMap connections = new CaseInsensitiveMap<>(); + private final ReadWriteLock connectionLock = new ReentrantReadWriteLock(); /** * Tab list handler */ @@ -278,10 +281,17 @@ public class BungeeCord extends ProxyServer stopListeners(); getLogger().info( "Closing pending connections" ); - getLogger().info( "Disconnecting " + connections.size() + " connections" ); - for ( UserConnection user : connections.values() ) + connectionLock.readLock().lock(); + try { - user.disconnect( getTranslation( "restart" ) ); + getLogger().info( "Disconnecting " + connections.size() + " connections" ); + for ( UserConnection user : connections.values() ) + { + user.disconnect( getTranslation( "restart" ) ); + } + } finally + { + connectionLock.readLock().unlock(); } getLogger().info( "Closing IO threads" ); @@ -310,9 +320,16 @@ public class BungeeCord extends ProxyServer */ public void broadcast(DefinedPacket packet) { - for ( UserConnection con : connections.values() ) + connectionLock.readLock().lock(); + try { - con.sendPacket( packet ); + for ( UserConnection con : connections.values() ) + { + con.sendPacket( packet ); + } + } finally + { + connectionLock.readLock().unlock(); } } @@ -357,7 +374,14 @@ public class BungeeCord extends ProxyServer @Override public ProxiedPlayer getPlayer(String name) { - return connections.get( name ); + connectionLock.readLock().lock(); + try + { + return connections.get( name ); + } finally + { + connectionLock.readLock().unlock(); + } } @Override @@ -435,4 +459,28 @@ public class BungeeCord extends ProxyServer { return ConsoleCommandSender.getInstance(); } + + public void addConnection(UserConnection con) + { + connectionLock.writeLock().lock(); + try + { + connections.put( con.getName(), con ); + } finally + { + connectionLock.writeLock().unlock(); + } + } + + public void removeConnection(UserConnection con) + { + connectionLock.writeLock().lock(); + try + { + connections.remove( con.getName() ); + } finally + { + connectionLock.writeLock().unlock(); + } + } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java index 8ed42f85..07cb99fd 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java @@ -27,7 +27,7 @@ public class UpstreamBridge extends PacketHandler this.bungee = bungee; this.con = con; - BungeeCord.getInstance().connections.put( con.getName(), con ); + BungeeCord.getInstance().addConnection( con ); bungee.getTabListHandler().onConnect( con ); con.sendPacket( BungeeCord.getInstance().registerChannels() ); @@ -51,7 +51,7 @@ public class UpstreamBridge extends PacketHandler PlayerDisconnectEvent event = new PlayerDisconnectEvent( con ); bungee.getPluginManager().callEvent( event ); bungee.getTabListHandler().onDisconnect( con ); - BungeeCord.getInstance().connections.remove( con.getName() ); //TODO: Better way, why do we need to raw access? + BungeeCord.getInstance().removeConnection( con ); if ( con.getServer() != null ) { diff --git a/proxy/src/test/java/net/md_5/bungee/util/CaseInsensitiveTest.java b/proxy/src/test/java/net/md_5/bungee/util/CaseInsensitiveTest.java index c5058450..88b378e4 100644 --- a/proxy/src/test/java/net/md_5/bungee/util/CaseInsensitiveTest.java +++ b/proxy/src/test/java/net/md_5/bungee/util/CaseInsensitiveTest.java @@ -13,8 +13,12 @@ public class CaseInsensitiveTest CaseInsensitiveMap map = new CaseInsensitiveMap<>(); map.put( "FOO", obj ); - Assert.assertTrue( map.contains( "foo" ) ); // Assert that it is case insensitive - Assert.assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Asert that case is preserved + Assert.assertTrue( map.contains( "foo" ) ); // Assert that contains is case insensitive + Assert.assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved + + // Assert that remove is case insensitive + map.remove( "FoO" ); + Assert.assertFalse( map.contains( "foo" ) ); } @Test @@ -23,6 +27,8 @@ public class CaseInsensitiveTest CaseInsensitiveSet set = new CaseInsensitiveSet(); set.add( "FOO" ); - Assert.assertTrue( set.contains( "foo" ) ); + Assert.assertTrue( set.contains( "foo" ) ); // Assert that contains is case insensitive + set.remove( "FoO" ); + Assert.assertFalse( set.contains( "foo" ) ); // Assert that remove is case insensitive } }