diff --git a/proxy/src/main/java/net/md_5/bungee/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/InitialHandler.java index 9238998f4..74060d4bb 100644 --- a/proxy/src/main/java/net/md_5/bungee/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/InitialHandler.java @@ -1,17 +1,15 @@ package net.md_5.bungee; import com.google.common.base.Preconditions; +import io.netty.channel.Channel; import java.io.EOFException; -import java.io.IOException; import java.net.InetSocketAddress; -import java.net.Socket; import java.util.ArrayList; import java.util.List; import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; import javax.crypto.SecretKey; import lombok.Getter; +import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ServerPing; @@ -21,6 +19,8 @@ import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.api.event.ProxyPingEvent; +import net.md_5.bungee.netty.CipherCodec; +import net.md_5.bungee.netty.PacketDecoder; import net.md_5.bungee.packet.DefinedPacket; import net.md_5.bungee.packet.Packet1Login; import net.md_5.bungee.packet.Packet2Handshake; @@ -31,16 +31,16 @@ import net.md_5.bungee.packet.PacketFDEncryptionRequest; import net.md_5.bungee.packet.PacketFEPing; import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketHandler; -import net.md_5.bungee.packet.PacketStream; import net.md_5.bungee.protocol.PacketDefinitions; +@RequiredArgsConstructor public class InitialHandler extends PacketHandler implements Runnable, PendingConnection { - private final Socket socket; + private final ProxyServer bungee; + private final Channel ch; @Getter private final ListenerInfo listener; - private PacketStream stream; private Packet1Login forgeLogin; private Packet2Handshake handshake; private PacketFDEncryptionRequest request; @@ -51,13 +51,6 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo 0, 0, 0, 0, 0, 2 } ); - public InitialHandler(Socket socket, ListenerInfo info) throws IOException - { - this.socket = socket; - this.listener = info; - stream = new PacketStream( socket.getInputStream(), socket.getOutputStream(), PacketDefinitions.VANILLA_PROTOCOL ); - } - private enum State { @@ -70,7 +63,8 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo Preconditions.checkState( thisState == State.LOGIN, "Not expecting FORGE LOGIN" ); Preconditions.checkState( forgeLogin == null, "Already received FORGE LOGIN" ); forgeLogin = login; - stream.setProtocol( PacketDefinitions.FORGE_PROTOCOL ); + + ch.pipeline().get( PacketDecoder.class ).setProtocol( PacketDefinitions.FORGE_PROTOCOL ); } @Override @@ -82,28 +76,17 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo @Override public void handle(PacketFEPing ping) throws Exception { - socket.setSoTimeout( 100 ); - boolean newPing = false; - try - { - socket.getInputStream().read(); - newPing = true; - } catch ( IOException ex ) - { - } - ServerPing pingevent = new ServerPing( BungeeCord.PROTOCOL_VERSION, BungeeCord.GAME_VERSION, - listener.getMotd(), ProxyServer.getInstance().getPlayers().size(), listener.getMaxPlayers() ); + listener.getMotd(), bungee.getPlayers().size(), listener.getMaxPlayers() ); - pingevent = ProxyServer.getInstance().getPluginManager().callEvent( new ProxyPingEvent( this, pingevent ) ).getResponse(); + pingevent = bungee.getPluginManager().callEvent( new ProxyPingEvent( this, pingevent ) ).getResponse(); - String response = ( newPing ) ? ChatColor.COLOR_CHAR + "1" + String response = ChatColor.COLOR_CHAR + "1" + "\00" + pingevent.getProtocolVersion() + "\00" + pingevent.getGameVersion() + "\00" + pingevent.getMotd() + "\00" + pingevent.getCurrentPlayers() - + "\00" + pingevent.getMaxPlayers() - : pingevent.getMotd() + ChatColor.COLOR_CHAR + pingevent.getCurrentPlayers() + ChatColor.COLOR_CHAR + pingevent.getMaxPlayers(); + + "\00" + pingevent.getMaxPlayers(); disconnect( response ); } @@ -111,9 +94,10 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo public void handle(Packet2Handshake handshake) throws Exception { Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" ); + Preconditions.checkArgument( handshake.username.length() <= 16, "Cannot have username longer than 16 characters" ); this.handshake = handshake; - stream.write( forgeMods ); - stream.write( request = EncryptionUtil.encryptRequest() ); + ch.write( forgeMods ); + ch.write( request = EncryptionUtil.encryptRequest() ); thisState = State.ENCRYPT; } @@ -129,7 +113,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo } // Check for multiple connections - ProxiedPlayer old = ProxyServer.getInstance().getPlayer( handshake.username ); + ProxiedPlayer old = bungee.getInstance().getPlayer( handshake.username ); if ( old != null ) { old.disconnect( "You are already connected to the server" ); @@ -137,15 +121,16 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo // fire login event LoginEvent event = new LoginEvent( this ); - ProxyServer.getInstance().getPluginManager().callEvent( event ); - if ( event.isCancelled() ) + if ( bungee.getPluginManager().callEvent( event ).isCancelled() ) { - throw new KickException( event.getCancelReason() ); + disconnect( event.getCancelReason() ); } - stream.write( new PacketFCEncryptionResponse() ); - stream = new PacketStream( new CipherInputStream( socket.getInputStream(), EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, shared ) ), - new CipherOutputStream( socket.getOutputStream(), EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, shared ) ), stream.getProtocol() ); + ch.write( new PacketFCEncryptionResponse() ); + + Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, shared ); + Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, shared ); + ch.pipeline().addBefore( "decoder", "cipher", new CipherCodec( encrypt, decrypt ) ); thisState = State.LOGIN; } @@ -186,23 +171,12 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo } @Override - public void disconnect(String reason) + public synchronized void disconnect(String reason) { - thisState = State.FINISHED; - try + if ( ch.isActive() ) { - stream.write( new PacketFFKick( reason ) ); - } catch ( IOException ioe ) - { - } finally - { - try - { - socket.shutdownOutput(); - socket.close(); - } catch ( IOException ioe2 ) - { - } + ch.write( new PacketFFKick( reason ) ); + ch.close(); } } @@ -227,6 +201,6 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo @Override public InetSocketAddress getAddress() { - return (InetSocketAddress) socket.getRemoteSocketAddress(); + return (InetSocketAddress) ch.remoteAddress(); } } 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 6b5ebe385..3a495488c 100644 --- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java @@ -2,6 +2,7 @@ package net.md_5.bungee; import com.google.common.base.Preconditions; import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.socket.nio.NioSocketChannel; @@ -9,10 +10,12 @@ import java.util.Queue; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectedEvent; import net.md_5.bungee.netty.ChannelBootstrapper; import net.md_5.bungee.packet.DefinedPacket; import net.md_5.bungee.packet.Packet1Login; +import net.md_5.bungee.packet.Packet9Respawn; import net.md_5.bungee.packet.PacketCDClientStatus; import net.md_5.bungee.packet.PacketFDEncryptionRequest; import net.md_5.bungee.packet.PacketFFKick; @@ -22,7 +25,9 @@ import net.md_5.bungee.packet.PacketStream; public class ServerConnector extends PacketHandler { - private final PacketStream stream; + private final ProxyServer bungee; + private final Channel ch; + private final UserConnection user; private Packet1Login loginPacket; private State thisState = State.ENCRYPT_REQUEST; @@ -45,15 +50,50 @@ public class ServerConnector extends PacketHandler ServerConnection server = new ServerConnection( socket, info, stream, connector.loginPacket ); ServerConnectedEvent event = new ServerConnectedEvent( user, server ); - ProxyServer.getInstance().getPluginManager().callEvent( event ); + bungee.getPluginManager().callEvent( event ); - stream.write( BungeeCord.getInstance().registerChannels() ); + ch.write( BungeeCord.getInstance().registerChannels() ); Queue packetQueue = ( (BungeeServerInfo) info ).getPacketQueue(); while ( !packetQueue.isEmpty() ) { - stream.write( packetQueue.poll() ); + ch.write( packetQueue.poll() ); } + + if ( user.getServer() == null ) + { + BungeeCord.getInstance().connections.put( user.getName(), this ); + bungee.getTabListHandler().onConnect( user ); + // Once again, first connection + clientEntityId = newServer.loginPacket.entityId; + serverEntityId = newServer.loginPacket.entityId; + // Set tab list size + Packet1Login s = newServer.loginPacket; + Packet1Login login = new Packet1Login( s.entityId, s.levelType, s.gameMode, (byte) s.dimension, s.difficulty, s.unused, (byte) pendingConnection.getListener().getTabListSize() ); + stream.write( login ); + stream.write( BungeeCord.getInstance().registerChannels() ); + } else + { + bungee.getTabListHandler().onServerChange( user ); + user.ch.write( new Packet9Respawn( (byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" ) ); + user.ch.write( new Packet9Respawn( (byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" ) ); + + Packet1Login login = newServer.loginPacket; + serverEntityId = login.entityId; + stream.write( new Packet9Respawn( login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType ) ); + + + // newServer.add(user) + + user.getServer().disconnect( "Quitting" ); + user.getServer().getInfo().removePlayer( user ); + + } + + // + + + thisState = State.FINISHED; } @@ -70,13 +110,17 @@ public class ServerConnector extends PacketHandler throw new KickException( kick.message ); } - public static void connect(final UserConnection user, final ServerInfo info, final boolean retry) + public static void connect(final UserConnection user, ServerInfo info, final boolean retry) { + ServerConnectEvent event = new ServerConnectEvent( user, info ); + ProxyServer.getInstance().getPluginManager().callEvent( event ); + final ServerInfo target = event.getTarget(); // Update in case the event changed target + new Bootstrap() .channel( NioSocketChannel.class ) .group( BungeeCord.getInstance().eventLoops ) .handler( ChannelBootstrapper.CLIENT ) - .remoteAddress( info.getAddress() ) + .remoteAddress( target.getAddress() ) .connect().addListener( new ChannelFutureListener() { @Override @@ -90,7 +134,7 @@ public class ServerConnector extends PacketHandler { future.channel().close(); ServerInfo def = ProxyServer.getInstance().getServers().get( user.getPendingConnection().getListener().getDefaultServer() ); - if ( retry && !info.equals( def ) ) + if ( retry && !target.equals( def ) ) { user.sendMessage( ChatColor.RED + "Could not connect to target server, you have been moved to the default server" ); connect( user, def, false ); diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index b2ed95e1b..f0c6f9edb 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -1,5 +1,6 @@ package net.md_5.bungee; +import com.google.common.base.Preconditions; import gnu.trove.set.hash.THashSet; import io.netty.channel.Channel; import java.net.InetSocketAddress; @@ -18,9 +19,6 @@ import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.PlayerDisconnectEvent; -import net.md_5.bungee.api.event.ServerConnectEvent; -import net.md_5.bungee.connection.DownstreamBridge; -import net.md_5.bungee.connection.UpstreamBridge; import net.md_5.bungee.packet.*; public final class UserConnection implements ProxiedPlayer @@ -57,10 +55,9 @@ public final class UserConnection implements ProxiedPlayer this.pendingConnection = pendingConnection; this.forgeLogin = forgeLogin; this.loginMessages = loginMessages; - name = handshake.username.substring( 0, Math.min( handshake.username.length(), 16 ) ); - displayName = name; - Collection g = ProxyServer.getInstance().getConfigurationAdapter().getGroups( name ); + + Collection g = bungee.getConfigurationAdapter().getGroups( name ); for ( String s : g ) { addGroups( s ); @@ -70,81 +67,14 @@ public final class UserConnection implements ProxiedPlayer @Override public void setDisplayName(String name) { - ProxyServer.getInstance().getTabListHandler().onDisconnect( this ); - displayName = name; - ProxyServer.getInstance().getTabListHandler().onConnect( this ); + Preconditions.checkArgument( name.length() <= 16, "Display name cannot be longer than 16 characters" ); + bungee.getTabListHandler().onDisconnect( this ); + bungee.getTabListHandler().onConnect( this ); } @Override public void connect(ServerInfo target) { - nextServer = target; - } - - public void connect(ServerInfo target, boolean force) - { - nextServer = null; - if ( server == null ) - { - // First join - BungeeCord.getInstance().connections.put( name, this ); - ProxyServer.getInstance().getTabListHandler().onConnect( this ); - } - - ServerConnectEvent event = new ServerConnectEvent( this, target ); - BungeeCord.getInstance().getPluginManager().callEvent( event ); - target = event.getTarget(); // Update in case the event changed target - - ProxyServer.getInstance().getTabListHandler().onServerChange( this ); - - reconnecting = true; - - if ( server != null ) - { - stream.write( new Packet9Respawn( (byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" ) ); - stream.write( new Packet9Respawn( (byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" ) ); - } - - ServerConnection newServer = ServerConnector.connect( this, target, true ); - if ( server == null ) - { - // Once again, first connection - clientEntityId = newServer.loginPacket.entityId; - serverEntityId = newServer.loginPacket.entityId; - // Set tab list size - Packet1Login s = newServer.loginPacket; - Packet1Login login = new Packet1Login( s.entityId, s.levelType, s.gameMode, (byte) s.dimension, s.difficulty, s.unused, (byte) pendingConnection.getListener().getTabListSize() ); - stream.write( login ); - stream.write( BungeeCord.getInstance().registerChannels() ); - - upBridge = new UpstreamBridge(); - upBridge.start(); - } else - { - try - { - downBridge.interrupt(); - downBridge.join(); - } catch ( InterruptedException ie ) - { - } - - server.disconnect( "Quitting" ); - server.getInfo().removePlayer( this ); - - Packet1Login login = newServer.loginPacket; - serverEntityId = login.entityId; - stream.write( new Packet9Respawn( login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType ) ); - } - - // Reconnect process has finished, lets get the player moving again - reconnecting = false; - - // Add to new - target.addPlayer( this ); - - // Start the bridges and move on - server = newServer; } @Override