diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java index efe6d0c2..3bd3d24a 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java @@ -1,8 +1,6 @@ package net.md_5.bungee; -import java.io.DataOutputStream; import java.net.InetSocketAddress; -import java.net.Socket; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import lombok.Getter; @@ -13,9 +11,6 @@ import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.packet.DefinedPacket; import net.md_5.bungee.packet.PacketFAPluginMessage; -import net.md_5.bungee.packet.PacketFFKick; -import net.md_5.bungee.packet.PacketStream; -import net.md_5.bungee.protocol.PacketDefinitions; public class BungeeServerInfo extends ServerInfo { @@ -44,31 +39,5 @@ public class BungeeServerInfo extends ServerInfo @Override public void ping(final Callback callback) { - new Thread() - { - @Override - public void run() - { - try ( Socket socket = new Socket(); ) - { - socket.connect( getAddress() ); - - DataOutputStream out = new DataOutputStream( socket.getOutputStream() ); - out.write( 0xFE ); - out.write( 0x01 ); - - PacketStream in = new PacketStream( socket.getInputStream(), PacketDefinitions.VANILLA_PROTOCOL ); - PacketFFKick response = new PacketFFKick( in.readPacket() ); - - String[] split = response.message.split( "\00" ); - - ServerPing ping = new ServerPing( Byte.parseByte( split[1] ), split[2], split[3], Integer.parseInt( split[4] ), Integer.parseInt( split[5] ) ); - callback.done( ping, null ); - } catch ( Throwable t ) - { - callback.done( null, t ); - } - } - }.start(); } } diff --git a/proxy/src/main/java/net/md_5/bungee/GenericConnection.java b/proxy/src/main/java/net/md_5/bungee/GenericConnection.java deleted file mode 100644 index 876add99..00000000 --- a/proxy/src/main/java/net/md_5/bungee/GenericConnection.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.md_5.bungee; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.Socket; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import static net.md_5.bungee.Logger.$; -import net.md_5.bungee.packet.PacketFFKick; -import net.md_5.bungee.packet.PacketStream; - -/** - * Class to represent a Minecraft connection. - */ -@EqualsAndHashCode -@RequiredArgsConstructor -public class GenericConnection -{ - - protected final Socket socket; - protected final PacketStream stream; - @Getter - public String name; - @Getter - public String displayName; - - /** - * Close the socket with the specified reason. - * - * @param reason to disconnect - */ - public void disconnect(String reason) - { - if ( socket.isClosed() ) - { - return; - } - log( "disconnected with " + reason ); - try - { - stream.write( new PacketFFKick( "[Proxy] " + reason ) ); - } catch ( IOException ex ) - { - } finally - { - try - { - socket.shutdownOutput(); - socket.close(); - } catch ( IOException ioe ) - { - } - } - } - - public void log(String message) - { - $().info( socket.getInetAddress() + ( ( name == null ) ? " " : " [" + name + "] " ) + message ); - } -} 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 3a495488..a1a4a83a 100644 --- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java @@ -1,12 +1,11 @@ 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; import java.util.Queue; +import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.config.ServerInfo; @@ -20,22 +19,17 @@ import net.md_5.bungee.packet.PacketCDClientStatus; import net.md_5.bungee.packet.PacketFDEncryptionRequest; import net.md_5.bungee.packet.PacketFFKick; import net.md_5.bungee.packet.PacketHandler; -import net.md_5.bungee.packet.PacketStream; +@RequiredArgsConstructor public class ServerConnector extends PacketHandler { private final ProxyServer bungee; private final Channel ch; private final UserConnection user; - private Packet1Login loginPacket; + private final ServerInfo target; private State thisState = State.ENCRYPT_REQUEST; - public ServerConnector(PacketStream stream) - { - this.stream = stream; - } - private enum State { @@ -46,54 +40,56 @@ public class ServerConnector extends PacketHandler public void handle(Packet1Login login) throws Exception { Preconditions.checkState( thisState == State.LOGIN, "Not exepcting LOGIN" ); - loginPacket = login; - ServerConnection server = new ServerConnection( socket, info, stream, connector.loginPacket ); + ServerConnection server = new ServerConnection( ch, target, login ); ServerConnectedEvent event = new ServerConnectedEvent( user, server ); bungee.getPluginManager().callEvent( event ); ch.write( BungeeCord.getInstance().registerChannels() ); - Queue packetQueue = ( (BungeeServerInfo) info ).getPacketQueue(); + Queue packetQueue = ( (BungeeServerInfo) target ).getPacketQueue(); while ( !packetQueue.isEmpty() ) { ch.write( packetQueue.poll() ); } - if ( user.getServer() == null ) + synchronized ( user.getSwitchMutex() ) { - 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" ) ); + if ( user.getServer() == null ) + { + BungeeCord.getInstance().connections.put( user.getName(), user ); + bungee.getTabListHandler().onConnect( user ); + // Once again, first connection + user.clientEntityId = login.entityId; + user.serverEntityId = login.entityId; + // Set tab list size + Packet1Login modLogin = new Packet1Login( + login.entityId, + login.levelType, + login.gameMode, + (byte) login.dimension, + login.difficulty, + login.unused, + (byte) user.getPendingConnection().getListener().getTabListSize() ); + ch.write( modLogin ); + ch.write( BungeeCord.getInstance().registerChannels() ); + } else + { + bungee.getTabListHandler().onServerChange( user ); + user.sendPacket( Packet9Respawn.DIM1_SWITCH ); + user.sendPacket( Packet9Respawn.DIM2_SWITCH ); - 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 ); + user.serverEntityId = login.entityId; + ch.write( new Packet9Respawn( login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType ) ); + // Add to new server + target.addPlayer( user ); + // Remove from old servers + user.getServer().disconnect( "Quitting" ); + user.getServer().getInfo().removePlayer( user ); + } } - // - - - thisState = State.FINISHED; } @@ -116,12 +112,7 @@ public class ServerConnector extends PacketHandler 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( target.getAddress() ) - .connect().addListener( new ChannelFutureListener() + ChannelBootstrapper.CLIENT.connectClient( info.getAddress() ).addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception 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 f0c6f9ed..0537fd83 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -4,10 +4,8 @@ import com.google.common.base.Preconditions; import gnu.trove.set.hash.THashSet; import io.netty.channel.Channel; import java.net.InetSocketAddress; -import java.net.Socket; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -35,22 +33,27 @@ public final class UserConnection implements ProxiedPlayer @Getter private ServerConnection server; // reconnect stuff - private int clientEntityId; - private int serverEntityId; + public int clientEntityId; + public int serverEntityId; // ping stuff public int trackingPingId; public long pingTime; @Getter + private String name; + @Getter + private String displayName; + @Getter @Setter private int ping = 1000; // Permissions - private final Collection playerGroups = new HashSet<>(); - private final THashSet permissions = new THashSet<>(); + private final Collection playerGroups = new THashSet<>(); + private final Collection permissions = new THashSet<>(); private final Object permMutex = new Object(); + @Getter + private final Object switchMutex = new Object(); - public UserConnection(Socket socket, PendingConnection pendingConnection, PacketStream stream, Packet2Handshake handshake, Packet1Login forgeLogin, List loginMessages) + public UserConnection(Channel channel, PendingConnection pendingConnection, Packet2Handshake handshake, Packet1Login forgeLogin, List loginMessages) { - super( socket, stream ); this.handshake = handshake; this.pendingConnection = pendingConnection; this.forgeLogin = forgeLogin; @@ -64,6 +67,11 @@ public final class UserConnection implements ProxiedPlayer } } + public void sendPacket(DefinedPacket p) + { + ch.write( p ); + } + @Override public void setDisplayName(String name) { 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 695af1c6..98c749af 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 @@ -109,8 +109,7 @@ public class DownstreamBridge extends PacketHandler ServerInfo server = bungee.getServerInfo( in.readUTF() ); if ( server != null ) { - connect( server, true ); - break outer; + con.connect( server ); } } if ( subChannel.equals( "IP" ) ) diff --git a/proxy/src/main/java/net/md_5/bungee/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java similarity index 85% rename from proxy/src/main/java/net/md_5/bungee/InitialHandler.java rename to proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index 74060d4b..6710dce2 100644 --- a/proxy/src/main/java/net/md_5/bungee/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -1,8 +1,7 @@ -package net.md_5.bungee; +package net.md_5.bungee.connection; import com.google.common.base.Preconditions; import io.netty.channel.Channel; -import java.io.EOFException; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; @@ -10,6 +9,10 @@ import javax.crypto.Cipher; import javax.crypto.SecretKey; import lombok.Getter; import lombok.RequiredArgsConstructor; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.EncryptionUtil; +import net.md_5.bungee.KickException; +import net.md_5.bungee.UserConnection; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ServerPing; @@ -21,7 +24,6 @@ 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; import net.md_5.bungee.packet.PacketCDClientStatus; @@ -34,7 +36,7 @@ import net.md_5.bungee.packet.PacketHandler; import net.md_5.bungee.protocol.PacketDefinitions; @RequiredArgsConstructor -public class InitialHandler extends PacketHandler implements Runnable, PendingConnection +public class InitialHandler extends PacketHandler implements PendingConnection { private final ProxyServer bungee; @@ -113,7 +115,7 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo } // Check for multiple connections - ProxiedPlayer old = bungee.getInstance().getPlayer( handshake.username ); + ProxiedPlayer old = bungee.getPlayer( handshake.username ); if ( old != null ) { old.disconnect( "You are already connected to the server" ); @@ -141,35 +143,12 @@ public class InitialHandler extends PacketHandler implements Runnable, PendingCo Preconditions.checkState( thisState == State.LOGIN, "Not expecting LOGIN" ); UserConnection userCon = new UserConnection( socket, this, stream, handshake, forgeLogin, loginMessages ); - ServerInfo server = ProxyServer.getInstance().getReconnectHandler().getServer( userCon ); - userCon.connect( server, true ); + ServerInfo server = bungee.getReconnectHandler().getServer( userCon ); + userCon.connect( server ); thisState = State.FINISHED; } - @Override - public void run() - { - try - { - while ( thisState != State.FINISHED ) - { - byte[] buf = stream.readPacket(); - DefinedPacket packet = DefinedPacket.packet( buf ); - packet.handle( this ); - } - } catch ( KickException ex ) - { - disconnect( "[Proxy - Kicked] " + ex.getMessage() ); - } catch ( EOFException ex ) - { - } catch ( Exception ex ) - { - disconnect( "[Proxy Error] " + Util.exception( ex ) ); - ex.printStackTrace(); - } - } - @Override public synchronized void disconnect(String reason) { diff --git a/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java new file mode 100644 index 00000000..ff4af4d0 --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/connection/PingHandler.java @@ -0,0 +1,41 @@ +package net.md_5.bungee.connection; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import lombok.RequiredArgsConstructor; +import net.md_5.bungee.api.Callback; +import net.md_5.bungee.api.ServerPing; +import net.md_5.bungee.packet.PacketFFKick; +import net.md_5.bungee.packet.PacketHandler; + +@RequiredArgsConstructor +public class PingHandler extends PacketHandler +{ + + private final Callback callback; + private static final ByteBuf pingBuf = Unpooled.wrappedBuffer( new byte[] + { + (byte) 0xFE, (byte) 0x01 + } ); + + @Override + public void connected(Channel channel) throws Exception + { + channel.write( pingBuf ); + } + + @Override + public void exception(Throwable t) throws Exception + { + callback.done( null, t ); + } + + @Override + public void handle(PacketFFKick kick) throws Exception + { + String[] split = kick.message.split( "\00" ); + ServerPing ping = new ServerPing( Byte.parseByte( split[1] ), split[2], split[3], Integer.parseInt( split[4] ), Integer.parseInt( split[5] ) ); + callback.done( ping, null ); + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/netty/ChannelBootstrapper.java b/proxy/src/main/java/net/md_5/bungee/netty/ChannelBootstrapper.java index 928ec25d..e4c81e7d 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/ChannelBootstrapper.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/ChannelBootstrapper.java @@ -1,14 +1,18 @@ package net.md_5.bungee.netty; +import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; +import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; +import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.timeout.ReadTimeoutHandler; import java.lang.reflect.Constructor; +import java.net.SocketAddress; import java.util.concurrent.TimeUnit; import net.md_5.bungee.BungeeCord; -import net.md_5.bungee.InitialHandler; +import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.ServerConnector; import net.md_5.bungee.packet.PacketHandler; import net.md_5.bungee.protocol.PacketDefinitions; @@ -20,6 +24,16 @@ public class ChannelBootstrapper extends ChannelInitializer public static ChannelBootstrapper SERVER = new ChannelBootstrapper( ServerConnector.class ); private final Constructor initial; + public ChannelFuture connectClient(SocketAddress remoteAddress) + { + return new Bootstrap() + .channel( NioSocketChannel.class ) + .group( BungeeCord.getInstance().eventLoops ) + .handler( this ) + .remoteAddress( remoteAddress ) + .connect(); + } + private ChannelBootstrapper(Class initialHandler) { try 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 38f37419..c404c92a 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 @@ -18,6 +18,18 @@ public class HandlerBoss extends ChannelInboundMessageHandlerAdapter this.handler = handler; } + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception + { + handler.connected( ctx.channel() ); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception + { + handler.disconnected( ctx.channel() ); + } + @Override protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { @@ -26,7 +38,7 @@ public class HandlerBoss extends ChannelInboundMessageHandlerAdapter DefinedPacket packet = DefinedPacket.packet( msg ); if ( packet != null ) { - handler.handle( packet ); + packet.handle( handler ); } else { handler.handle( msg ); diff --git a/proxy/src/main/java/net/md_5/bungee/packet/Packet9Respawn.java b/proxy/src/main/java/net/md_5/bungee/packet/Packet9Respawn.java index 2619d3f8..a6e09e1b 100644 --- a/proxy/src/main/java/net/md_5/bungee/packet/Packet9Respawn.java +++ b/proxy/src/main/java/net/md_5/bungee/packet/Packet9Respawn.java @@ -8,6 +8,8 @@ import lombok.ToString; public class Packet9Respawn extends DefinedPacket { + public static final Packet9Respawn DIM1_SWITCH = new Packet9Respawn( (byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" ); + public static final Packet9Respawn DIM2_SWITCH = new Packet9Respawn( (byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" ); public int dimension; public byte difficulty; public byte gameMode; diff --git a/proxy/src/main/java/net/md_5/bungee/packet/PacketHandler.java b/proxy/src/main/java/net/md_5/bungee/packet/PacketHandler.java index 7826d0af..e5462daf 100644 --- a/proxy/src/main/java/net/md_5/bungee/packet/PacketHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/packet/PacketHandler.java @@ -1,6 +1,7 @@ package net.md_5.bungee.packet; import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; public abstract class PacketHandler { @@ -10,16 +11,23 @@ public abstract class PacketHandler throw new UnsupportedOperationException( "No handler defined for packet " + msg.getClass() ); } + public void connected(Channel channel) throws Exception + { + } + + public void disconnected(Channel channel) throws Exception + { + } + + public void exception(Throwable t) throws Exception + { + } + public void handle(ByteBuf buf) throws Exception { nop( buf ); } - public void handle(DefinedPacket packet) throws Exception - { - nop( packet ); - } - public void handle(Packet0KeepAlive alive) throws Exception { nop( alive );