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 }