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    }