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 }