Basically done with login

This commit is contained in:
md_5 2013-10-11 21:36:28 +11:00
parent 7121c20338
commit dbdae87ec6
14 changed files with 257 additions and 64 deletions

View File

@ -13,7 +13,7 @@ public class ServerPing
/** /**
* Numeric protocol version supported by the server. * Numeric protocol version supported by the server.
*/ */
private final byte protocolVersion; private final int protocolVersion;
/** /**
* Human readable game version. * Human readable game version.
*/ */

View File

@ -19,10 +19,25 @@ import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.EncryptionResponse; import net.md_5.bungee.protocol.packet.EncryptionResponse;
import net.md_5.bungee.protocol.packet.LoginRequest; import net.md_5.bungee.protocol.packet.LoginRequest;
import net.md_5.bungee.protocol.packet.LoginSuccess; import net.md_5.bungee.protocol.packet.LoginSuccess;
import net.md_5.bungee.protocol.packet.PingPacket;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
public abstract class AbstractPacketHandler public abstract class AbstractPacketHandler
{ {
public void handle(PingPacket ping) throws Exception
{
}
public void handle(StatusRequest statusRequest) throws Exception
{
}
public void handle(StatusResponse statusResponse) throws Exception
{
}
public void handle(Handshake handshake) throws Exception public void handle(Handshake handshake) throws Exception
{ {
} }

View File

@ -23,6 +23,8 @@ public class MinecraftCodec extends MessageToMessageCodec<ByteBuf, DefinedPacket
ByteBuf buf = ctx.alloc().buffer(); ByteBuf buf = ctx.alloc().buffer();
DefinedPacket.writeVarInt( prot.getId( msg.getClass() ), buf ); DefinedPacket.writeVarInt( prot.getId( msg.getClass() ), buf );
msg.write( buf ); msg.write( buf );
out.add( buf );
} }
@Override @Override

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.protocol; package net.md_5.bungee.protocol;
import com.google.common.base.Preconditions;
import gnu.trove.map.TObjectIntMap; import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.map.hash.TObjectIntHashMap;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -13,12 +14,15 @@ import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login; import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.LoginRequest; import net.md_5.bungee.protocol.packet.LoginRequest;
import net.md_5.bungee.protocol.packet.LoginSuccess; import net.md_5.bungee.protocol.packet.LoginSuccess;
import net.md_5.bungee.protocol.packet.PingPacket;
import net.md_5.bungee.protocol.packet.PlayerListItem; import net.md_5.bungee.protocol.packet.PlayerListItem;
import net.md_5.bungee.protocol.packet.PluginMessage; import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.protocol.packet.Respawn; import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay; import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective; import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore; import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
import net.md_5.bungee.protocol.packet.TabComplete; import net.md_5.bungee.protocol.packet.TabComplete;
import net.md_5.bungee.protocol.packet.Team; import net.md_5.bungee.protocol.packet.Team;
@ -63,6 +67,11 @@ public enum Protocol
{ {
{ {
TO_CLIENT.registerPacket( 0x00, StatusResponse.class );
TO_CLIENT.registerPacket( 0x01, PingPacket.class );
TO_SERVER.registerPacket( 0x00, StatusRequest.class );
TO_SERVER.registerPacket( 0x01, PingPacket.class );
} }
}, },
//2 //2
@ -140,6 +149,8 @@ public enum Protocol
final int getId(Class<? extends DefinedPacket> packet) final int getId(Class<? extends DefinedPacket> packet)
{ {
Preconditions.checkArgument( packetMap.containsKey( packet ), "Cannot get ID for packet " + packet );
return packetMap.get( packet ); return packetMap.get( packet );
} }
} }

View File

@ -17,7 +17,7 @@ public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>
out.ensureWritable( headerLen + bodyLen ); out.ensureWritable( headerLen + bodyLen );
DefinedPacket.writeVarInt( bodyLen, out ); DefinedPacket.writeVarInt( bodyLen, out );
out.writeBytes( msg, msg.readerIndex(), bodyLen ); out.writeBytes( msg );
} }
private static int varintSize(int paramInt) private static int varintSize(int paramInt)

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class PingPacket extends DefinedPacket
{
private long time;
@Override
public void read(ByteBuf buf)
{
time = buf.readLong();
}
@Override
public void write(ByteBuf buf)
{
buf.writeLong( time );
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -0,0 +1,31 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class StatusRequest extends DefinedPacket
{
@Override
public void read(ByteBuf buf)
{
}
@Override
public void write(ByteBuf buf)
{
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class StatusResponse extends DefinedPacket
{
private String response;
@Override
public void read(ByteBuf buf)
{
response = readString( buf );
}
@Override
public void write(ByteBuf buf)
{
writeString( response, buf );
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -0,0 +1,40 @@
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.command.ConsoleCommandSender;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author michael
*/
public class Test
{
public static void main(String[] args) throws Exception
{
System.setProperty( "java.net.preferIPv4Stack", "true" );
BungeeCord bungee = new BungeeCord();
ProxyServer.setInstance( bungee );
bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() );
bungee.start();
while ( bungee.isRunning )
{
String line = bungee.getConsoleReader().readLine( ">" );
if ( line != null )
{
if ( !bungee.getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line ) )
{
bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" );
}
}
}
}
}

View File

@ -3,10 +3,11 @@ package net.md_5.bungee.connection;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.netty.util.concurrent.ScheduledFuture; import java.math.BigInteger;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -16,7 +17,6 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.md_5.bungee.BungeeCord; import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.EncryptionUtil; import net.md_5.bungee.EncryptionUtil;
import net.md_5.bungee.PacketConstants;
import net.md_5.bungee.UserConnection; import net.md_5.bungee.UserConnection;
import net.md_5.bungee.Util; import net.md_5.bungee.Util;
import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.Callback;
@ -37,7 +37,6 @@ import net.md_5.bungee.netty.CipherDecoder;
import net.md_5.bungee.netty.CipherEncoder; import net.md_5.bungee.netty.CipherEncoder;
import net.md_5.bungee.netty.PacketHandler; import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.MinecraftInput;
import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.packet.Login; import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.Handshake;
@ -48,8 +47,12 @@ import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.Kick; import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.api.AbstractReconnectHandler; import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.event.PlayerHandshakeEvent; import net.md_5.bungee.api.event.PlayerHandshakeEvent;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol; import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.packet.LoginRequest; import net.md_5.bungee.protocol.packet.LoginRequest;
import net.md_5.bungee.protocol.packet.LoginSuccess;
import net.md_5.bungee.protocol.packet.PingPacket;
import net.md_5.bungee.protocol.packet.StatusRequest;
@RequiredArgsConstructor @RequiredArgsConstructor
public class InitialHandler extends PacketHandler implements PendingConnection public class InitialHandler extends PacketHandler implements PendingConnection
@ -82,7 +85,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
}; };
@Getter @Getter
private boolean onlineMode = BungeeCord.getInstance().config.isOnlineMode(); private boolean onlineMode = BungeeCord.getInstance().config.isOnlineMode();
private ScheduledFuture<?> pingFuture;
private InetSocketAddress vHost; private InetSocketAddress vHost;
private byte version = -1; private byte version = -1;
@Getter @Getter
@ -91,7 +93,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private enum State private enum State
{ {
HANDSHAKE, ENCRYPT, LOGIN, FINISHED; HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, LOGIN, FINISHED;
} }
@Override @Override
@ -100,6 +102,14 @@ public class InitialHandler extends PacketHandler implements PendingConnection
this.ch = channel; this.ch = channel;
} }
@Override
public void handle(PacketWrapper packet) throws Exception
{
int len = DefinedPacket.readVarInt( packet.buf );
int id = DefinedPacket.readVarInt( packet.buf );
throw new UnsupportedOperationException( "Cannot handle unknown packet at login!" );
}
@Override @Override
public void exception(Throwable t) throws Exception public void exception(Throwable t) throws Exception
{ {
@ -109,22 +119,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
@Override @Override
public void handle(PluginMessage pluginMessage) throws Exception public void handle(PluginMessage pluginMessage) throws Exception
{ {
if ( pluginMessage.getTag().equals( "MC|PingHost" ) )
{
if ( pingFuture.cancel( false ) )
{
MinecraftInput in = pluginMessage.getMCStream();
version = in.readByte();
String connectHost = in.readString();
int connectPort = in.readInt();
this.vHost = new InetSocketAddress( connectHost, connectPort );
respondToPing();
}
return;
}
// TODO: Unregister? // TODO: Unregister?
if ( pluginMessage.getTag().equals( "REGISTER" ) ) if ( pluginMessage.getTag().equals( "REGISTER" ) )
{ {
@ -135,7 +129,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
} }
} }
private void respondToPing() @Override
public void handle(StatusRequest statusRequest) throws Exception
{ {
ServerInfo forced = AbstractReconnectHandler.getForcedHost( this ); ServerInfo forced = AbstractReconnectHandler.getForcedHost( this );
final String motd = ( forced != null ) ? forced.getMotd() : listener.getMotd(); final String motd = ( forced != null ) ? forced.getMotd() : listener.getMotd();
@ -167,22 +162,17 @@ public class InitialHandler extends PacketHandler implements PendingConnection
forced.ping( pingBack ); forced.ping( pingBack );
} else } else
{ {
// pingBack.done( new ServerPing( bungee.getProtocolVersion(), bungee.getGameVersion(), motd, bungee.getOnlineCount(), listener.getMaxPlayers() ), null ); pingBack.done( new ServerPing( bungee.getProtocolVersion(), bungee.getGameVersion(), motd, bungee.getOnlineCount(), listener.getMaxPlayers() ), null );
} }
} }
/*
@Override @Override
public void handle(PacketFEPing ping) throws Exception public void handle(PingPacket ping) throws Exception
{ {
pingFuture = ch.getHandle().eventLoop().schedule( new Runnable() Preconditions.checkState( thisState == State.PING, "Not expecting PING" );
{ unsafe.sendPacket( ping );
@Override disconnect( "" );
public void run() }
{
respondToPing();
}
}, 200, TimeUnit.MILLISECONDS );
}*/
@Override @Override
public void handle(Handshake handshake) throws Exception public void handle(Handshake handshake) throws Exception
@ -206,9 +196,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
case 1: case 1:
// Ping // Ping
thisState = State.STATUS;
ch.setProtocol( Protocol.STATUS ); ch.setProtocol( Protocol.STATUS );
break; break;
case 2: case 2:
thisState = State.USERNAME;
ch.setProtocol( Protocol.LOGIN ); ch.setProtocol( Protocol.LOGIN );
// Login // Login
break; break;
@ -220,6 +212,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
@Override @Override
public void handle(LoginRequest loginRequest) throws Exception public void handle(LoginRequest loginRequest) throws Exception
{ {
Preconditions.checkState( thisState == State.USERNAME, "Not expecting USERNAME" );
this.loginRequest = loginRequest; this.loginRequest = loginRequest;
if ( getName().length() > 16 ) if ( getName().length() > 16 )
@ -242,8 +235,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection
return; return;
} }
unsafe().sendPacket( PacketConstants.I_AM_BUNGEE ); // TODO: Nuuuu Mojang why u do this
unsafe().sendPacket( PacketConstants.FORGE_MOD_REQUEST ); // unsafe().sendPacket( PacketConstants.I_AM_BUNGEE );
// unsafe().sendPacket( PacketConstants.FORGE_MOD_REQUEST );
unsafe().sendPacket( request = EncryptionUtil.encryptRequest( this.onlineMode ) ); unsafe().sendPacket( request = EncryptionUtil.encryptRequest( this.onlineMode ) );
thisState = State.ENCRYPT; thisState = State.ENCRYPT;
@ -261,9 +255,18 @@ public class InitialHandler extends PacketHandler implements PendingConnection
if ( this.onlineMode ) if ( this.onlineMode )
{ {
String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" ); String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" );
String encID = URLEncoder.encode( InitialHandler.this.request.getServerId(), "UTF-8" );
String authURL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + encID; MessageDigest sha = MessageDigest.getInstance( "SHA-1" );
for ( byte[] bit : new byte[][]
{
request.getServerId().getBytes( "ISO_8859_1" ), sharedKey.getEncoded(), EncryptionUtil.keys.getPublic().getEncoded()
} )
{
sha.update( bit );
}
String encodedHash = URLEncoder.encode( new BigInteger( sha.digest() ).toString( 16 ), "UTF-8" );
String authURL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + encodedHash;
Callback<String> handler = new Callback<String>() Callback<String> handler = new Callback<String>()
{ {
@ -272,16 +275,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
if ( error == null ) if ( error == null )
{ {
JsonObject obj = BungeeCord.getInstance().gson.fromJson( result, JsonObject.class ); LoginResult obj = BungeeCord.getInstance().gson.fromJson( result, LoginResult.class );
if ( obj != null ) if ( obj != null )
{ {
JsonElement id = obj.get( "id" ); UUID = obj.getId();
if ( id != null ) finish();
{ return;
UUID = id.getAsString();
finish();
return;
}
} }
disconnect( "Not authenticated with Minecraft.net" ); disconnect( "Not authenticated with Minecraft.net" );
} else } else
@ -330,15 +329,26 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
if ( ch.getHandle().isActive() ) if ( ch.getHandle().isActive() )
{ {
unsafe().sendPacket( new EncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
try if ( onlineMode )
{ {
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey ); unsafe().sendPacket( new EncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) ); try
} catch ( GeneralSecurityException ex ) {
{ Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey );
disconnect( "Cipher error: " + Util.exception( ex ) ); ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
} catch ( GeneralSecurityException ex )
{
disconnect( "Cipher error: " + Util.exception( ex ) );
}
} }
if ( UUID == null )
{
UUID = java.util.UUID.randomUUID().toString();
}
unsafe.sendPacket( new LoginSuccess( BungeeCord.getInstance().gson.toJson( new LoginResult( UUID ) ) ) );
ch.setProtocol( Protocol.GAME );
} }
} }
} ); } );
@ -380,7 +390,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
if ( !ch.isClosed() ) if ( !ch.isClosed() )
{ {
unsafe().sendPacket( new Kick( reason ) ); unsafe().sendPacket( new Kick( BungeeCord.getInstance().gson.toJson( reason ) ) );
ch.close(); ch.close();
} }
} }

View File

@ -0,0 +1,12 @@
package net.md_5.bungee.connection;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class LoginResult
{
private String id;
}

View File

@ -33,10 +33,10 @@ public class ChannelWrapper
if ( packet instanceof PacketWrapper ) if ( packet instanceof PacketWrapper )
{ {
( (PacketWrapper) packet ).setReleased( true ); ( (PacketWrapper) packet ).setReleased( true );
ch.write( ( (PacketWrapper) packet ).buf ); ch.write( ( (PacketWrapper) packet ).buf, ch.voidPromise() );
} else } else
{ {
ch.write( packet ); ch.write( packet, ch.voidPromise() );
} }
ch.flush(); ch.flush();
} }

View File

@ -12,8 +12,6 @@ import net.md_5.bungee.connection.CancelSendSignal;
import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.connection.PingHandler; import net.md_5.bungee.connection.PingHandler;
import net.md_5.bungee.protocol.BadPacketException; import net.md_5.bungee.protocol.BadPacketException;
import net.md_5.bungee.protocol.MinecraftCodec;
import net.md_5.bungee.protocol.Protocol;
/** /**
* This class is a primitive wrapper for {@link PacketHandler} instances tied to * This class is a primitive wrapper for {@link PacketHandler} instances tied to

View File

@ -76,10 +76,10 @@ public class PipelineUtils
{ {
// IP_TOS is not supported (Windows XP / Windows Server 2003) // IP_TOS is not supported (Windows XP / Windows Server 2003)
} }
ch.pipeline().addLast( FRAME_PREPENDER, framePrepender );
ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) ); ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) );
ch.pipeline().addLast( FRAME_DECODER, new Varint21FrameDecoder() ); ch.pipeline().addLast( FRAME_DECODER, new Varint21FrameDecoder() );
ch.pipeline().addLast( FRAME_PREPENDER, framePrepender );
ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() ); ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
} }
}; };