    001    package net.minecraft.network;
    002
    003    import java.io.IOException;
    004    import java.io.Serializable;
    005    import java.net.InetAddress;
    006    import java.net.Socket;
    007    import java.security.PrivateKey;
    008    import java.security.PublicKey;
    009    import java.util.Arrays;
    010    import java.util.Iterator;
    011    import java.util.List;
    012    import java.util.Random;
    013    import java.util.logging.Logger;
    014    import javax.crypto.SecretKey;
    015
    016    import cpw.mods.fml.common.network.FMLNetworkHandler;
    017    import net.minecraft.entity.player.EntityPlayer;
    018    import net.minecraft.entity.player.EntityPlayerMP;
    019    import net.minecraft.network.packet.NetHandler;
    020    import net.minecraft.network.packet.Packet;
    021    import net.minecraft.network.packet.Packet1Login;
    022    import net.minecraft.network.packet.Packet205ClientCommand;
    023    import net.minecraft.network.packet.Packet250CustomPayload;
    024    import net.minecraft.network.packet.Packet252SharedKey;
    025    import net.minecraft.network.packet.Packet253ServerAuthData;
    026    import net.minecraft.network.packet.Packet254ServerPing;
    027    import net.minecraft.network.packet.Packet255KickDisconnect;
    028    import net.minecraft.network.packet.Packet2ClientProtocol;
    029    import net.minecraft.server.MinecraftServer;
    030    import net.minecraft.server.dedicated.DedicatedServerListenThread;
    031    import net.minecraft.server.management.ServerConfigurationManager;
    032    import net.minecraft.util.StringUtils;
    033
    034    public class NetLoginHandler extends NetHandler
    035    {
    036        private byte[] field_72536_d;
    037
    038        /** The Minecraft logger. */
    039        public static Logger logger = Logger.getLogger("Minecraft");
    040
    041        /** The Random object used to generate serverId hex strings. */
    042        private static Random rand = new Random();
    043        public TcpConnection myTCPConnection;
    044        public boolean connectionComplete = false;
    045
    046        /** Reference to the MinecraftServer object. */
    047        private MinecraftServer mcServer;
    048        private int connectionTimer = 0;
    049        public String clientUsername = null;
    050        private volatile boolean field_72544_i = false;
    051
    052        /** server ID that is randomly generated by this login handler. */
    053        private String loginServerId = "";
    054        private SecretKey field_72542_k = null;
    055
    056        public NetLoginHandler(MinecraftServer par1MinecraftServer, Socket par2Socket, String par3Str) throws IOException
    057        {
    058            this.mcServer = par1MinecraftServer;
    059            this.myTCPConnection = new TcpConnection(par2Socket, par3Str, this, par1MinecraftServer.getKeyPair().getPrivate());
    060            this.myTCPConnection.field_74468_e = 0;
    061        }
    062
    063        /**
    064         * Logs the user in if a login packet is found, otherwise keeps processing network packets unless the timeout has
    065         * occurred.
    066         */
    067        public void tryLogin()
    068        {
    069            if (this.field_72544_i)
    070            {
    071                this.initializePlayerConnection();
    072            }
    073
    074            if (this.connectionTimer++ == 6000)
    075            {
    076                this.raiseErrorAndDisconnect("Took too long to log in");
    077            }
    078            else
    079            {
    080                this.myTCPConnection.processReadPackets();
    081            }
    082        }
    083
    084        public void raiseErrorAndDisconnect(String par1Str)
    085        {
    086            try
    087            {
    088                logger.info("Disconnecting " + this.getUsernameAndAddress() + ": " + par1Str);
    089                this.myTCPConnection.addToSendQueue(new Packet255KickDisconnect(par1Str));
    090                this.myTCPConnection.serverShutdown();
    091                this.connectionComplete = true;
    092            }
    093            catch (Exception var3)
    094            {
    095                var3.printStackTrace();
    096            }
    097        }
    098
    099        public void handleClientProtocol(Packet2ClientProtocol par1Packet2ClientProtocol)
    100        {
    101            this.clientUsername = par1Packet2ClientProtocol.getUsername();
    102
    103            if (!this.clientUsername.equals(StringUtils.stripControlCodes(this.clientUsername)))
    104            {
    105                this.raiseErrorAndDisconnect("Invalid username!");
    106            }
    107            else
    108            {
    109                PublicKey var2 = this.mcServer.getKeyPair().getPublic();
    110
    111                if (par1Packet2ClientProtocol.getProtocolVersion() != 49)
    112                {
    113                    if (par1Packet2ClientProtocol.getProtocolVersion() > 49)
    114                    {
    115                        this.raiseErrorAndDisconnect("Outdated server!");
    116                    }
    117                    else
    118                    {
    119                        this.raiseErrorAndDisconnect("Outdated client!");
    120                    }
    121                }
    122                else
    123                {
    124                    this.loginServerId = this.mcServer.isServerInOnlineMode() ? Long.toString(rand.nextLong(), 16) : "-";
    125                    this.field_72536_d = new byte[4];
    126                    rand.nextBytes(this.field_72536_d);
    127                    this.myTCPConnection.addToSendQueue(new Packet253ServerAuthData(this.loginServerId, var2, this.field_72536_d));
    128                }
    129            }
    130        }
    131
    132        public void handleSharedKey(Packet252SharedKey par1Packet252SharedKey)
    133        {
    134            PrivateKey var2 = this.mcServer.getKeyPair().getPrivate();
    135            this.field_72542_k = par1Packet252SharedKey.func_73303_a(var2);
    136
    137            if (!Arrays.equals(this.field_72536_d, par1Packet252SharedKey.func_73302_b(var2)))
    138            {
    139                this.raiseErrorAndDisconnect("Invalid client reply");
    140            }
    141
    142            this.myTCPConnection.addToSendQueue(new Packet252SharedKey());
    143        }
    144
    145        public void handleClientCommand(Packet205ClientCommand par1Packet205ClientCommand)
    146        {
    147            if (par1Packet205ClientCommand.forceRespawn == 0)
    148            {
    149                if (this.mcServer.isServerInOnlineMode())
    150                {
    151                    (new ThreadLoginVerifier(this)).start();
    152                }
    153                else
    154                {
    155                    this.field_72544_i = true;
    156                }
    157            }
    158        }
    159
    160        public void handleLogin(Packet1Login par1Packet1Login)
    161        {
    162            FMLNetworkHandler.handleLoginPacketOnServer(this, par1Packet1Login);
    163        }
    164
    165        /**
    166         * on success the specified username is connected to the minecraftInstance, otherwise they are packet255'd
    167         */
    168        public void initializePlayerConnection()
    169        {
    170            FMLNetworkHandler.onConnectionReceivedFromClient(this, this.mcServer, this.myTCPConnection.getSocketAddress(), this.clientUsername);
    171        }
    172
    173        public void completeConnection(String var1)
    174        {
    175
    176            if (var1 != null)
    177            {
    178                this.raiseErrorAndDisconnect(var1);
    179            }
    180            else
    181            {
    182                EntityPlayerMP var2 = this.mcServer.getConfigurationManager().createPlayerForUser(this.clientUsername);
    183
    184                if (var2 != null)
    185                {
    186                    this.mcServer.getConfigurationManager().initializeConnectionToPlayer(this.myTCPConnection, var2);
    187                }
    188            }
    189
    190            this.connectionComplete = true;
    191        }
    192
    193        public void handleErrorMessage(String par1Str, Object[] par2ArrayOfObj)
    194        {
    195            logger.info(this.getUsernameAndAddress() + " lost connection");
    196            this.connectionComplete = true;
    197        }
    198
    199        /**
    200         * Handle a server ping packet.
    201         */
    202        public void handleServerPing(Packet254ServerPing par1Packet254ServerPing)
    203        {
    204            try
    205            {
    206                ServerConfigurationManager var2 = this.mcServer.getConfigurationManager();
    207                String var3 = null;
    208
    209                if (par1Packet254ServerPing.field_82559_a == 1)
    210                {
    211                    List var4 = Arrays.asList(new Serializable[] {Integer.valueOf(1), Integer.valueOf(49), this.mcServer.getMinecraftVersion(), this.mcServer.getMOTD(), Integer.valueOf(var2.getCurrentPlayerCount()), Integer.valueOf(var2.getMaxPlayers())});
    212                    Object var6;
    213
    214                    for (Iterator var5 = var4.iterator(); var5.hasNext(); var3 = var3 + var6.toString().replaceAll("\u0000", ""))
    215                    {
    216                        var6 = var5.next();
    217
    218                        if (var3 == null)
    219                        {
    220                            var3 = "\u00a7";
    221                        }
    222                        else
    223                        {
    224                            var3 = var3 + "\u0000";
    225                        }
    226                    }
    227                }
    228                else
    229                {
    230                    var3 = this.mcServer.getMOTD() + "\u00a7" + var2.getCurrentPlayerCount() + "\u00a7" + var2.getMaxPlayers();
    231                }
    232
    233                InetAddress var8 = null;
    234
    235                if (this.myTCPConnection.getSocket() != null)
    236                {
    237                    var8 = this.myTCPConnection.getSocket().getInetAddress();
    238                }
    239
    240                this.myTCPConnection.addToSendQueue(new Packet255KickDisconnect(var3));
    241                this.myTCPConnection.serverShutdown();
    242
    243                if (var8 != null && this.mcServer.getNetworkThread() instanceof DedicatedServerListenThread)
    244                {
    245                    ((DedicatedServerListenThread)this.mcServer.getNetworkThread()).func_71761_a(var8);
    246                }
    247
    248                this.connectionComplete = true;
    249            }
    250            catch (Exception var7)
    251            {
    252                var7.printStackTrace();
    253            }
    254        }
    255
    256        /**
    257         * Default handler called for packets that don't have their own handlers in NetClientHandler; currentlly does
    258         * nothing.
    259         */
    260        public void unexpectedPacket(Packet par1Packet)
    261        {
    262            this.raiseErrorAndDisconnect("Protocol error");
    263        }
    264
    265        public String getUsernameAndAddress()
    266        {
    267            return this.clientUsername != null ? this.clientUsername + " [" + this.myTCPConnection.getSocketAddress().toString() + "]" : this.myTCPConnection.getSocketAddress().toString();
    268        }
    269
    270        /**
    271         * determine if it is a server handler
    272         */
    273        public boolean isServerHandler()
    274        {
    275            return true;
    276        }
    277
    278        /**
    279         * Returns the server Id randomly generated by this login handler.
    280         */
    281        static String getServerId(NetLoginHandler par0NetLoginHandler)
    282        {
    283            return par0NetLoginHandler.loginServerId;
    284        }
    285
    286        /**
    287         * Returns the reference to Minecraft Server.
    288         */
    289        static MinecraftServer getLoginMinecraftServer(NetLoginHandler par0NetLoginHandler)
    290        {
    291            return par0NetLoginHandler.mcServer;
    292        }
    293
    294        static SecretKey func_72525_c(NetLoginHandler par0NetLoginHandler)
    295        {
    296            return par0NetLoginHandler.field_72542_k;
    297        }
    298
    299        /**
    300         * Returns the connecting client username.
    301         */
    302        static String getClientUsername(NetLoginHandler par0NetLoginHandler)
    303        {
    304            return par0NetLoginHandler.clientUsername;
    305        }
    306
    307        public static boolean func_72531_a(NetLoginHandler par0NetLoginHandler, boolean par1)
    308        {
    309            return par0NetLoginHandler.field_72544_i = par1;
    310        }
    311
    312
    313        public void handleCustomPayload(Packet250CustomPayload par1Packet250CustomPayload)
    314        {
    315            FMLNetworkHandler.handlePacket250Packet(par1Packet250CustomPayload, myTCPConnection, this);
    316        }
    317
    318        @Override
    319        public void handleVanilla250Packet(Packet250CustomPayload payload)
    320        {
    321            // NOOP for login
    322        }
    323
    324        public EntityPlayer getPlayer()
    325        {
    326            return null;
    327        };
    328    }