diff --git a/api/src/main/java/net/md_5/bungee/api/ServerPing.java b/api/src/main/java/net/md_5/bungee/api/ServerPing.java index 314a1d2711..27b51849ba 100644 --- a/api/src/main/java/net/md_5/bungee/api/ServerPing.java +++ b/api/src/main/java/net/md_5/bungee/api/ServerPing.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.ToString; import net.md_5.bungee.Util; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; @@ -16,6 +17,7 @@ * Minecraft client server list, or hitting it with a packet 0xFE. */ @Data +@ToString(exclude = "favicon") @NoArgsConstructor @AllArgsConstructor public class ServerPing diff --git a/config/src/main/java/net/md_5/bungee/config/Configuration.java b/config/src/main/java/net/md_5/bungee/config/Configuration.java index 1366f44916..2b29614ae1 100644 --- a/config/src/main/java/net/md_5/bungee/config/Configuration.java +++ b/config/src/main/java/net/md_5/bungee/config/Configuration.java @@ -7,10 +7,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor(access = AccessLevel.PACKAGE) public final class Configuration { @@ -28,6 +25,25 @@ public Configuration(Configuration defaults) this( new LinkedHashMap(), defaults ); } + Configuration(Map map, Configuration defaults) + { + this.self = new LinkedHashMap<>(); + this.defaults = defaults; + + for ( Map.Entry entry : map.entrySet() ) + { + String key = ( entry.getKey() == null ) ? "null" : entry.getKey().toString(); + + if ( entry.getValue() instanceof Map ) + { + this.self.put( key, new Configuration( (Map) entry.getValue(), ( defaults == null ) ? null : defaults.getSection( key ) ) ); + } else + { + this.self.put( key, entry.getValue() ); + } + } + } + private Configuration getSectionFor(String path) { int index = path.indexOf( SEPARATOR ); @@ -40,15 +56,11 @@ private Configuration getSectionFor(String path) Object section = self.get( root ); if ( section == null ) { - section = new LinkedHashMap<>(); + section = new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ); self.put( root, section ); } - if ( section instanceof Configuration ) - { - return (Configuration) section; - } - return new Configuration( (Map) section, ( defaults == null ) ? null : defaults.getSectionFor( path ) ); + return (Configuration) section; } private String getChild(String path) @@ -71,9 +83,19 @@ public T get(String path, T def) val = section.get( getChild( path ), def ); } + if ( val == null && def instanceof Configuration ) + { + self.put( path, def ); + } + return ( val != null ) ? (T) val : def; } + public boolean contains(String path) + { + return get( path, null ) != null; + } + public Object get(String path) { return get( path, getDefault( path ) ); @@ -106,7 +128,7 @@ public void set(String path, Object value) public Configuration getSection(String path) { Object def = getDefault( path ); - return new Configuration( (Map) ( get( path, ( def instanceof Map ) ? def : Collections.EMPTY_MAP ) ), ( defaults == null ) ? null : defaults.getSection( path ) ); + return (Configuration) get( path, ( def instanceof Configuration ) ? def : new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ) ); } /** diff --git a/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java b/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java index 0a936025d2..db8aa4bed5 100644 --- a/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java +++ b/config/src/main/java/net/md_5/bungee/config/YamlConfiguration.java @@ -13,6 +13,10 @@ import lombok.NoArgsConstructor; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.representer.Represent; +import org.yaml.snakeyaml.representer.Representer; @NoArgsConstructor(access = AccessLevel.PACKAGE) public class YamlConfiguration extends ConfigurationProvider @@ -23,9 +27,24 @@ public class YamlConfiguration extends ConfigurationProvider @Override protected Yaml initialValue() { + Representer representer = new Representer() + { + { + representers.put( Configuration.class, new Represent() + { + @Override + public Node representData(Object data) + { + return represent( ( (Configuration) data ).self ); + } + } ); + } + }; + DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK ); - return new Yaml( options ); + + return new Yaml( new Constructor(), representer, options ); } }; diff --git a/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java b/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java index 8f15168ff2..589d3ee46d 100644 --- a/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java +++ b/config/src/test/java/net/md_5/bungee/config/YamlConfigurationTest.java @@ -10,7 +10,7 @@ public class YamlConfigurationTest { - private String document = "" + private static final String TEST_DOCUMENT = "" + "receipt: Oz-Ware Purchase Invoice\n" + "date: 2012-08-06\n" + "customer:\n" @@ -43,11 +43,21 @@ public class YamlConfigurationTest + " Road to the Emerald City.\n" + " Pay no attention to the\n" + " man behind the curtain."; + private static final String NUMBER_TEST = "" + + "someKey:\n" + + " 1: 1\n" + + " 2: 2\n" + + " 3: 3\n" + + " 4: 4"; + private static final String NULL_TEST = "" + + "null:\n" + + " null: object\n" + + " object: null\n"; @Test public void testConfig() throws Exception { - Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( document ); + Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( TEST_DOCUMENT ); testSection( conf ); StringWriter sw = new StringWriter(); @@ -77,5 +87,42 @@ private void testSection(Configuration conf) conf.set( "receipt", null ); Assert.assertEquals( null, conf.get( "receipt" ) ); Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) ); + + Configuration newSection = conf.getSection( "new.section" ); + newSection.set( "value", "foo" ); + Assert.assertEquals( "foo", conf.get( "new.section.value" ) ); + + conf.set( "other.new.section", "bar" ); + Assert.assertEquals( "bar", conf.get( "other.new.section" ) ); + + Assert.assertTrue( conf.contains( "customer.given" ) ); + Assert.assertTrue( customer.contains( "given" ) ); + + Assert.assertFalse( conf.contains( "customer.foo" ) ); + Assert.assertFalse( customer.contains( "foo" ) ); + } + + @Test + public void testNumberedKeys() + { + Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( NUMBER_TEST ); + + Configuration section = conf.getSection( "someKey" ); + for ( String key : section.getKeys() ) + { + // empty + } + } + + @Test + public void testNull() + { + Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( NULL_TEST ); + + Assert.assertEquals( "object", conf.get( "null.null" ) ); + Assert.assertEquals( "object", conf.getSection( "null" ).get( "null" ) ); + + Assert.assertEquals( null, conf.get( "null.object" ) ); + Assert.assertEquals( "", conf.getString( "null.object" ) ); } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java index c418c8ea4d..543487229c 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java @@ -49,6 +49,14 @@ public static void writeArray(byte[] b, ByteBuf buf) buf.writeBytes( b ); } + public static byte[] toArray(ByteBuf buf) + { + byte[] ret = new byte[ buf.readableBytes() ]; + buf.readBytes( ret ); + + return ret; + } + public static byte[] readArray(ByteBuf buf) { return readArray( buf, buf.readableBytes() ); diff --git a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java index 6ed247fe95..755b48223c 100644 --- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java @@ -193,9 +193,9 @@ public void handle(Login login) throws Exception } else { - ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer(); - DefinedPacket.writeString(bungee.getName() + " (" + bungee.getVersion() + ")", brand); - user.unsafe().sendPacket(new PluginMessage("MC|Brand", DefinedPacket.readArray( brand ), handshakeHandler.isServerForge())); + ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer(); + DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")", brand ); + user.unsafe().sendPacket( new PluginMessage( "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler.isServerForge() ) ); brand.release(); } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java index 8ea114d07d..0b029816c5 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java @@ -4,6 +4,7 @@ import java.io.DataInput; import com.google.common.base.Objects; +import com.google.common.base.Preconditions; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -221,6 +222,9 @@ public void handle(PluginMessage pluginMessage) throws Exception ByteBuf brand = Unpooled.wrappedBuffer(pluginMessage.getData()); String serverBrand = DefinedPacket.readString(brand); brand.release(); + + Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); + brand = ByteBufAllocator.DEFAULT.heapBuffer(); DefinedPacket.writeString(bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand); pluginMessage.setData(DefinedPacket.readArray( brand )); @@ -229,6 +233,9 @@ public void handle(PluginMessage pluginMessage) throws Exception else { String serverBrand = new String(pluginMessage.getData(), "UTF-8"); + + Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); + pluginMessage.setData((bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand).getBytes("UTF-8")); } // changes in the packet are ignored so we need to send it manually 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 f8a17b3974..ecb0485911 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 @@ -86,14 +86,17 @@ public void disconnected(ChannelWrapper channel) throws Exception @Override public boolean shouldHandle(PacketWrapper packet) throws Exception { - return con.getServer() != null; + return con.getServer() != null || packet.packet instanceof PluginMessage; } @Override public void handle(PacketWrapper packet) throws Exception { - con.getEntityRewrite().rewriteServerbound( packet.buf, con.getClientEntityId(), con.getServerEntityId() ); - con.getServer().getCh().write( packet ); + if ( con.getServer() != null ) + { + con.getEntityRewrite().rewriteServerbound( packet.buf, con.getClientEntityId(), con.getServerEntityId() ); + con.getServer().getCh().write( packet ); + } } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java index 94a164e3f6..7a49d21f03 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java @@ -111,11 +111,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E { handler, cause.getCause().getMessage() } ); - } else if ( cause instanceof IOException ) + } else if ( cause instanceof IOException || ( cause instanceof IllegalStateException && handler instanceof InitialHandler ) ) { - ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - IOException: {1}", new Object[] + ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - {1}: {2}", new Object[] { - handler, cause.getMessage() + handler, cause.getClass().getSimpleName(), cause.getMessage() } ); } else {