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 }