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 }