· 7 years ago · Apr 13, 2018, 03:38 PM
1package net.minecraft.src;
2
3import java.io.BufferedOutputStream;
4import java.io.DataInputStream;
5import java.io.DataOutputStream;
6import java.io.IOException;
7import java.io.InputStream;
8import java.net.Socket;
9import java.net.SocketAddress;
10import java.net.SocketException;
11import java.security.PrivateKey;
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.Iterator;
15import java.util.List;
16import java.util.concurrent.atomic.AtomicInteger;
17import javax.crypto.SecretKey;
18
19import dot.atlantis.client.events.list.EventReceivePacket;
20import dot.atlantis.client.main.Client;
21import net.minecraft.client.Minecraft;
22
23public class TcpConnection implements INetworkManager
24{
25 public static AtomicInteger field_74471_a = new AtomicInteger();
26 public static AtomicInteger field_74469_b = new AtomicInteger();
27
28 /** The object used for synchronization on the send queue. */
29 private final Object sendQueueLock;
30 private final ILogAgent field_98215_i;
31
32 /** The socket used by this network manager. */
33 private Socket networkSocket;
34
35 /** The InetSocketAddress of the remote endpoint */
36 private final SocketAddress remoteSocketAddress;
37
38 /** The input stream connected to the socket. */
39 private volatile DataInputStream socketInputStream;
40
41 /** The output stream connected to the socket. */
42 private volatile DataOutputStream socketOutputStream;
43
44 /** Whether the network is currently operational. */
45 private volatile boolean isRunning;
46
47 /**
48 * Whether this network manager is currently terminating (and should ignore further errors).
49 */
50 private volatile boolean isTerminating;
51
52 /**
53 * Linked list of packets that have been read and are awaiting processing.
54 */
55 private List readPackets;
56
57 /** Linked list of packets awaiting sending. */
58 private List dataPackets;
59
60 /** Linked list of packets with chunk data that are awaiting sending. */
61 private List chunkDataPackets;
62
63 /** A reference to the NetHandler object. */
64 private NetHandler theNetHandler;
65
66 /**
67 * Whether this server is currently terminating. If this is a client, this is always false.
68 */
69 private boolean isServerTerminating;
70
71 /** The thread used for writing. */
72 private Thread writeThread;
73
74 /** The thread used for reading. */
75 private Thread readThread;
76
77 /** A String indicating why the network has shutdown. */
78 private String terminationReason;
79 private Object[] field_74480_w;
80 private int field_74490_x;
81
82 /**
83 * The length in bytes of the packets in both send queues (data and chunkData).
84 */
85 private int sendQueueByteLength;
86 public static int[] field_74470_c = new int[256];
87 public static int[] field_74467_d = new int[256];
88 public int field_74468_e;
89 boolean isInputBeingDecrypted;
90 boolean isOutputEncrypted;
91 private SecretKey sharedKeyForEncryption;
92 private PrivateKey field_74463_A;
93
94 /**
95 * Delay for sending pending chunk data packets (as opposed to pending non-chunk data packets)
96 */
97 private int chunkDataPacketsDelay;
98
99 public TcpConnection(ILogAgent par1ILogAgent, Socket par2Socket, String par3Str, NetHandler par4NetHandler) throws IOException
100 {
101 this(par1ILogAgent, par2Socket, par3Str, par4NetHandler, (PrivateKey)null);
102 }
103
104 public TcpConnection(ILogAgent par1ILogAgent, Socket par2Socket, String par3Str, NetHandler par4NetHandler, PrivateKey par5PrivateKey) throws IOException
105 {
106 this.sendQueueLock = new Object();
107 this.isRunning = true;
108 this.isTerminating = false;
109 this.readPackets = Collections.synchronizedList(new ArrayList());
110 this.dataPackets = Collections.synchronizedList(new ArrayList());
111 this.chunkDataPackets = Collections.synchronizedList(new ArrayList());
112 this.isServerTerminating = false;
113 this.terminationReason = "";
114 this.field_74490_x = 0;
115 this.sendQueueByteLength = 0;
116 this.field_74468_e = 0;
117 this.isInputBeingDecrypted = false;
118 this.isOutputEncrypted = false;
119 this.sharedKeyForEncryption = null;
120 this.field_74463_A = null;
121 this.chunkDataPacketsDelay = 50;
122 this.field_74463_A = par5PrivateKey;
123 this.networkSocket = par2Socket;
124 this.field_98215_i = par1ILogAgent;
125 this.remoteSocketAddress = par2Socket.getRemoteSocketAddress();
126 this.theNetHandler = par4NetHandler;
127
128 try
129 {
130 par2Socket.setSoTimeout(30000);
131 par2Socket.setTrafficClass(24);
132 }
133 catch (SocketException var7)
134 {
135 System.err.println(var7.getMessage());
136 }
137
138 this.socketInputStream = new DataInputStream(par2Socket.getInputStream());
139 this.socketOutputStream = new DataOutputStream(new BufferedOutputStream(par2Socket.getOutputStream(), 5120));
140 this.readThread = new TcpReaderThread(this, par3Str + " read thread");
141 this.writeThread = new TcpWriterThread(this, par3Str + " write thread");
142 this.readThread.start();
143 this.writeThread.start();
144 }
145
146 public void closeConnections()
147 {
148 this.wakeThreads();
149 this.writeThread = null;
150 this.readThread = null;
151 }
152
153 /**
154 * Sets the NetHandler for this NetworkManager. Server-only.
155 */
156 public void setNetHandler(NetHandler par1NetHandler)
157 {
158 this.theNetHandler = par1NetHandler;
159 }
160
161 /**
162 * Adds the packet to the correct send queue (chunk data packets go to a separate queue).
163 */
164 public void addToSendQueue(Packet par1Packet)
165 {
166 EventReceivePacket packet = new EventReceivePacket(par1Packet);
167 Client.getClient().getEventManager().hook(packet);
168 if (packet.isCancelled())
169 return;
170 if (!this.isServerTerminating)
171 {
172 Object var2 = this.sendQueueLock;
173
174 synchronized (this.sendQueueLock)
175 {
176 this.dataPackets.add(par1Packet);
177 }
178 }
179 }
180
181 /**
182 * Sends a data packet if there is one to send, or sends a chunk data packet if there is one and the counter is up,
183 * or does nothing.
184 */
185 private boolean sendPacket()
186 {
187 boolean var1 = false;
188
189 try
190 {
191 int[] var10000;
192 int var10001;
193 Packet var2;
194
195 if (this.field_74468_e == 0 || !this.dataPackets.isEmpty() && System.currentTimeMillis() - ((Packet)this.dataPackets.get(0)).creationTimeMillis >= (long)this.field_74468_e)
196 {
197 var2 = this.func_74460_a(false);
198
199 if (var2 != null)
200 {
201 Packet.writePacket(var2, this.socketOutputStream);
202
203 if (var2 instanceof Packet252SharedKey && !this.isOutputEncrypted)
204 {
205 if (!this.theNetHandler.isServerHandler())
206 {
207 this.sharedKeyForEncryption = ((Packet252SharedKey)var2).getSharedKey();
208 }
209
210 this.encryptOuputStream();
211 }
212
213 var10000 = field_74467_d;
214 var10001 = var2.getPacketId();
215 var10000[var10001] += var2.getPacketSize() + 1;
216 var1 = true;
217 }
218 }
219
220 if (this.chunkDataPacketsDelay-- <= 0 && (this.field_74468_e == 0 || !this.chunkDataPackets.isEmpty() && System.currentTimeMillis() - ((Packet)this.chunkDataPackets.get(0)).creationTimeMillis >= (long)this.field_74468_e))
221 {
222 var2 = this.func_74460_a(true);
223
224 if (var2 != null)
225 {
226 EventReceivePacket packet = new EventReceivePacket(var2);
227 Client.getClient().getEventManager().hook(packet);
228 if (packet.isCancelled())
229 return false;
230 Packet.writePacket(var2, this.socketOutputStream);
231 var10000 = field_74467_d;
232 var10001 = var2.getPacketId();
233 var10000[var10001] += var2.getPacketSize() + 1;
234 this.chunkDataPacketsDelay = 0;
235 var1 = true;
236 }
237 }
238
239 return var1;
240 }
241 catch (Exception var3)
242 {
243 if (!this.isTerminating)
244 {
245 this.onNetworkError(var3);
246 }
247
248 return false;
249 }
250 }
251
252 private Packet func_74460_a(boolean par1)
253 {
254 Packet var2 = null;
255 List var3 = par1 ? this.chunkDataPackets : this.dataPackets;
256 Object var4 = this.sendQueueLock;
257
258 synchronized (this.sendQueueLock)
259 {
260 while (!var3.isEmpty() && var2 == null)
261 {
262 var2 = (Packet)var3.remove(0);
263 this.sendQueueByteLength -= var2.getPacketSize() + 1;
264
265 if (this.func_74454_a(var2, par1))
266 {
267 var2 = null;
268 }
269 }
270
271 return var2;
272 }
273 }
274
275 private boolean func_74454_a(Packet par1Packet, boolean par2)
276 {
277 if (!par1Packet.isRealPacket())
278 {
279 return false;
280 }
281 else
282 {
283 List var3 = par2 ? this.chunkDataPackets : this.dataPackets;
284 Iterator var4 = var3.iterator();
285 Packet var5;
286
287 do
288 {
289 if (!var4.hasNext())
290 {
291 return false;
292 }
293
294 var5 = (Packet)var4.next();
295 }
296 while (var5.getPacketId() != par1Packet.getPacketId());
297
298 return par1Packet.containsSameEntityIDAs(var5);
299 }
300 }
301
302 /**
303 * Wakes reader and writer threads
304 */
305 public void wakeThreads()
306 {
307 if (this.readThread != null)
308 {
309 this.readThread.interrupt();
310 }
311
312 if (this.writeThread != null)
313 {
314 this.writeThread.interrupt();
315 }
316 }
317
318 /**
319 * Reads a single packet from the input stream and adds it to the read queue. If no packet is read, it shuts down
320 * the network.
321 */
322 private boolean readPacket()
323 {
324 boolean var1 = false;
325
326 try
327 {
328 Packet var2 = Packet.readPacket(this.field_98215_i, this.socketInputStream, this.theNetHandler.isServerHandler(), this.networkSocket);
329
330 if (var2 != null)
331 {
332 if (var2 instanceof Packet252SharedKey && !this.isInputBeingDecrypted)
333 {
334 if (this.theNetHandler.isServerHandler())
335 {
336 this.sharedKeyForEncryption = ((Packet252SharedKey)var2).getSharedKey(this.field_74463_A);
337 }
338
339 this.decryptInputStream();
340 }
341
342 int[] var10000 = field_74470_c;
343 int var10001 = var2.getPacketId();
344 var10000[var10001] += var2.getPacketSize() + 1;
345
346 if (!this.isServerTerminating)
347 {
348 if (var2.canProcessAsync() && this.theNetHandler.canProcessPacketsAsync())
349 {
350 this.field_74490_x = 0;
351 EventReceivePacket packet = new EventReceivePacket(var2);
352 Client.getClient().getEventManager().hook(packet);
353 if (packet.isCancelled())
354 return false;
355
356 var2.processPacket(this.theNetHandler);
357 }
358 else
359 {
360 this.readPackets.add(var2);
361 }
362 }
363
364 var1 = true;
365 }
366 else
367 {
368 this.networkShutdown("disconnect.endOfStream", new Object[0]);
369 }
370
371 return var1;
372 }
373 catch (Exception var3)
374 {
375 if (!this.isTerminating)
376 {
377 this.onNetworkError(var3);
378 }
379
380 return false;
381 }
382 }
383
384 /**
385 * Used to report network errors and causes a network shutdown.
386 */
387 private void onNetworkError(Exception par1Exception)
388 {
389 par1Exception.printStackTrace();
390 this.networkShutdown("disconnect.genericReason", new Object[] {"Internal exception: " + par1Exception.toString()});
391 }
392
393 /**
394 * Shuts down the network with the specified reason. Closes all streams and sockets, spawns NetworkMasterThread to
395 * stop reading and writing threads.
396 */
397 public void networkShutdown(String par1Str, Object ... par2ArrayOfObj)
398 {
399 if (this.isRunning)
400 {
401 this.isTerminating = true;
402 this.terminationReason = par1Str;
403 this.field_74480_w = par2ArrayOfObj;
404 this.isRunning = false;
405 (new TcpMasterThread(this)).start();
406
407 try
408 {
409 this.socketInputStream.close();
410 }
411 catch (Throwable var6)
412 {
413 ;
414 }
415
416 try
417 {
418 this.socketOutputStream.close();
419 }
420 catch (Throwable var5)
421 {
422 ;
423 }
424
425 try
426 {
427 this.networkSocket.close();
428 }
429 catch (Throwable var4)
430 {
431 ;
432 }
433
434 this.socketInputStream = null;
435 this.socketOutputStream = null;
436 this.networkSocket = null;
437 }
438 }
439
440 /**
441 * Checks timeouts and processes all pending read packets.
442 */
443 public void processReadPackets()
444 {
445 if (this.readPackets.isEmpty())
446 {
447 if (this.field_74490_x++ == 1200)
448 {
449 this.networkShutdown("disconnect.timeout", new Object[0]);
450 }
451 }
452 else
453 {
454 this.field_74490_x = 0;
455 }
456
457 int var1 = 1000;
458
459 while (!this.readPackets.isEmpty() && var1-- >= 0)
460 {
461 Packet var2 = (Packet)this.readPackets.remove(0);
462 EventReceivePacket packet = new EventReceivePacket(var2);
463 Client.getClient().getEventManager().hook(packet);
464 if (packet.isCancelled())
465 return;
466 var2.processPacket(this.theNetHandler);
467 }
468 this.wakeThreads();
469
470 if (this.isTerminating && this.readPackets.isEmpty())
471 {
472 this.theNetHandler.handleErrorMessage(this.terminationReason, this.field_74480_w);
473 }
474 }
475
476 /**
477 * Return the InetSocketAddress of the remote endpoint
478 */
479 public SocketAddress getSocketAddress()
480 {
481 return this.remoteSocketAddress;
482 }
483
484 /**
485 * Shuts down the server. (Only actually used on the server)
486 */
487 public void serverShutdown()
488 {
489 if (!this.isServerTerminating)
490 {
491 this.wakeThreads();
492 this.isServerTerminating = true;
493 this.readThread.interrupt();
494 (new TcpMonitorThread(this)).start();
495 }
496 }
497
498 private void decryptInputStream() throws IOException
499 {
500 this.isInputBeingDecrypted = true;
501 InputStream var1 = this.networkSocket.getInputStream();
502 this.socketInputStream = new DataInputStream(CryptManager.decryptInputStream(this.sharedKeyForEncryption, var1));
503 }
504
505 /**
506 * flushes the stream and replaces it with an encryptedOutputStream
507 */
508 private void encryptOuputStream() throws IOException
509 {
510 this.socketOutputStream.flush();
511 this.isOutputEncrypted = true;
512 BufferedOutputStream var1 = new BufferedOutputStream(CryptManager.encryptOuputStream(this.sharedKeyForEncryption, this.networkSocket.getOutputStream()), 5120);
513 this.socketOutputStream = new DataOutputStream(var1);
514 }
515
516 /**
517 * returns 0 for memoryConnections
518 */
519 public int packetSize()
520 {
521 return this.chunkDataPackets.size();
522 }
523
524 public Socket getSocket()
525 {
526 return this.networkSocket;
527 }
528
529 /**
530 * Whether the network is operational.
531 */
532 static boolean isRunning(TcpConnection par0TcpConnection)
533 {
534 return par0TcpConnection.isRunning;
535 }
536
537 /**
538 * Is the server terminating? Client side aways returns false.
539 */
540 static boolean isServerTerminating(TcpConnection par0TcpConnection)
541 {
542 return par0TcpConnection.isServerTerminating;
543 }
544
545 /**
546 * Static accessor to readPacket.
547 */
548 static boolean readNetworkPacket(TcpConnection par0TcpConnection)
549 {
550 return par0TcpConnection.readPacket();
551 }
552
553 /**
554 * Static accessor to sendPacket.
555 */
556 static boolean sendNetworkPacket(TcpConnection par0TcpConnection)
557 {
558 return par0TcpConnection.sendPacket();
559 }
560
561 static DataOutputStream getOutputStream(TcpConnection par0TcpConnection)
562 {
563 return par0TcpConnection.socketOutputStream;
564 }
565
566 /**
567 * Gets whether the Network manager is terminating.
568 */
569 static boolean isTerminating(TcpConnection par0TcpConnection)
570 {
571 return par0TcpConnection.isTerminating;
572 }
573
574 /**
575 * Sends the network manager an error
576 */
577 static void sendError(TcpConnection par0TcpConnection, Exception par1Exception)
578 {
579 par0TcpConnection.onNetworkError(par1Exception);
580 }
581
582 /**
583 * Returns the read thread.
584 */
585 static Thread getReadThread(TcpConnection par0TcpConnection)
586 {
587 return par0TcpConnection.readThread;
588 }
589
590 /**
591 * Returns the write thread.
592 */
593 static Thread getWriteThread(TcpConnection par0TcpConnection)
594 {
595 return par0TcpConnection.writeThread;
596 }
597}