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    }