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