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