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