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