Redo parts of login and connection sequences
This commit is contained in:
parent
b6e76f4054
commit
644deee3c6
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<DefinedPacket> 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 );
|
||||
|
@ -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<String> g = ProxyServer.getInstance().getConfigurationAdapter().getGroups( name );
|
||||
|
||||
Collection<String> 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
|
||||
|
Loading…
Reference in New Issue
Block a user