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