mirror of
https://git.zelz.net/catfoolyou/Project164.git
synced 2025-12-14 08:37:41 +00:00
sp-server
This commit is contained in:
484
sp-server/src_aux/TcpConnection.java
Normal file
484
sp-server/src_aux/TcpConnection.java
Normal file
@@ -0,0 +1,484 @@
|
||||
package net.minecraft.src;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class TcpConnection implements INetworkManager {
|
||||
public static AtomicInteger field_74471_a = new AtomicInteger();
|
||||
public static AtomicInteger field_74469_b = new AtomicInteger();
|
||||
|
||||
/** The object used for synchronization on the send queue. */
|
||||
private final Object sendQueueLock = new Object();
|
||||
private final ILogAgent field_98215_i;
|
||||
|
||||
/** The socket used by this network manager. */
|
||||
private Socket networkSocket;
|
||||
|
||||
/** The InetSocketAddress of the remote endpoint */
|
||||
private final SocketAddress remoteSocketAddress;
|
||||
|
||||
/** The input stream connected to the socket. */
|
||||
private volatile DataInputStream socketInputStream;
|
||||
|
||||
/** The output stream connected to the socket. */
|
||||
private volatile DataOutputStream socketOutputStream;
|
||||
|
||||
/** Whether the network is currently operational. */
|
||||
private volatile boolean isRunning = true;
|
||||
|
||||
/**
|
||||
* Whether this network manager is currently terminating (and should ignore
|
||||
* further errors).
|
||||
*/
|
||||
private volatile boolean isTerminating = false;
|
||||
|
||||
/**
|
||||
* Linked list of packets that have been read and are awaiting processing.
|
||||
*/
|
||||
private List readPackets = Collections.synchronizedList(new ArrayList());
|
||||
|
||||
/** Linked list of packets awaiting sending. */
|
||||
private List dataPackets = Collections.synchronizedList(new ArrayList());
|
||||
|
||||
/** Linked list of packets with chunk data that are awaiting sending. */
|
||||
private List chunkDataPackets = Collections.synchronizedList(new ArrayList());
|
||||
|
||||
/** A reference to the NetHandler object. */
|
||||
private NetHandler theNetHandler;
|
||||
|
||||
/**
|
||||
* Whether this server is currently terminating. If this is a client, this is
|
||||
* always false.
|
||||
*/
|
||||
private boolean isServerTerminating = false;
|
||||
|
||||
/** The thread used for writing. */
|
||||
private Thread writeThread;
|
||||
|
||||
/** The thread used for reading. */
|
||||
private Thread readThread;
|
||||
|
||||
/** A String indicating why the network has shutdown. */
|
||||
private String terminationReason = "";
|
||||
private Object[] field_74480_w;
|
||||
private int field_74490_x = 0;
|
||||
|
||||
/**
|
||||
* The length in bytes of the packets in both send queues (data and chunkData).
|
||||
*/
|
||||
private int sendQueueByteLength = 0;
|
||||
public static int[] field_74470_c = new int[256];
|
||||
public static int[] field_74467_d = new int[256];
|
||||
public int field_74468_e = 0;
|
||||
boolean isInputBeingDecrypted = false;
|
||||
boolean isOutputEncrypted = false;
|
||||
private SecretKey sharedKeyForEncryption = null;
|
||||
private PrivateKey field_74463_A = null;
|
||||
|
||||
/**
|
||||
* Delay for sending pending chunk data packets (as opposed to pending non-chunk
|
||||
* data packets)
|
||||
*/
|
||||
private int chunkDataPacketsDelay = 50;
|
||||
|
||||
public TcpConnection(ILogAgent par1ILogAgent, Socket par2Socket, String par3Str, NetHandler par4NetHandler,
|
||||
PrivateKey par5PrivateKey) throws IOException {
|
||||
this.field_74463_A = par5PrivateKey;
|
||||
this.networkSocket = par2Socket;
|
||||
this.field_98215_i = par1ILogAgent;
|
||||
this.remoteSocketAddress = par2Socket.getRemoteSocketAddress();
|
||||
this.theNetHandler = par4NetHandler;
|
||||
|
||||
try {
|
||||
par2Socket.setSoTimeout(30000);
|
||||
par2Socket.setTrafficClass(24);
|
||||
} catch (SocketException var7) {
|
||||
System.err.println(var7.getMessage());
|
||||
}
|
||||
|
||||
this.socketInputStream = new DataInputStream(par2Socket.getInputStream());
|
||||
this.socketOutputStream = new DataOutputStream(new BufferedOutputStream(par2Socket.getOutputStream(), 5120));
|
||||
this.readThread = new TcpReaderThread(this, par3Str + " read thread");
|
||||
this.writeThread = new TcpWriterThread(this, par3Str + " write thread");
|
||||
this.readThread.start();
|
||||
this.writeThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the NetHandler for this NetworkManager. Server-only.
|
||||
*/
|
||||
public void setNetHandler(NetHandler par1NetHandler) {
|
||||
this.theNetHandler = par1NetHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the packet to the correct send queue (chunk data packets go to a
|
||||
* separate queue).
|
||||
*/
|
||||
public void addToSendQueue(Packet par1Packet) {
|
||||
if (!this.isServerTerminating) {
|
||||
Object var2 = this.sendQueueLock;
|
||||
|
||||
synchronized (this.sendQueueLock) {
|
||||
this.sendQueueByteLength += par1Packet.getPacketSize() + 1;
|
||||
this.dataPackets.add(par1Packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, or does nothing.
|
||||
*/
|
||||
private boolean sendPacket() {
|
||||
boolean var1 = false;
|
||||
|
||||
try {
|
||||
int[] var10000;
|
||||
int var10001;
|
||||
Packet var2;
|
||||
|
||||
if (this.field_74468_e == 0 || !this.dataPackets.isEmpty() && System.currentTimeMillis()
|
||||
- ((Packet) this.dataPackets.get(0)).creationTimeMillis >= (long) this.field_74468_e) {
|
||||
var2 = this.func_74460_a(false);
|
||||
|
||||
if (var2 != null) {
|
||||
Packet.writePacket(var2, this.socketOutputStream);
|
||||
|
||||
if (var2 instanceof Packet252SharedKey && !this.isOutputEncrypted) {
|
||||
if (!this.theNetHandler.isServerHandler()) {
|
||||
this.sharedKeyForEncryption = ((Packet252SharedKey) var2).getSharedKey();
|
||||
}
|
||||
|
||||
this.encryptOuputStream();
|
||||
}
|
||||
|
||||
var10000 = field_74467_d;
|
||||
var10001 = var2.getPacketId();
|
||||
var10000[var10001] += var2.getPacketSize() + 1;
|
||||
var1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
var2 = this.func_74460_a(true);
|
||||
|
||||
if (var2 != null) {
|
||||
Packet.writePacket(var2, this.socketOutputStream);
|
||||
var10000 = field_74467_d;
|
||||
var10001 = var2.getPacketId();
|
||||
var10000[var10001] += var2.getPacketSize() + 1;
|
||||
this.chunkDataPacketsDelay = 0;
|
||||
var1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
return var1;
|
||||
} catch (Exception var3) {
|
||||
if (!this.isTerminating) {
|
||||
this.onNetworkError(var3);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Packet func_74460_a(boolean par1) {
|
||||
Packet var2 = null;
|
||||
List var3 = par1 ? this.chunkDataPackets : this.dataPackets;
|
||||
Object var4 = this.sendQueueLock;
|
||||
|
||||
synchronized (this.sendQueueLock) {
|
||||
while (!var3.isEmpty() && var2 == null) {
|
||||
var2 = (Packet) var3.remove(0);
|
||||
this.sendQueueByteLength -= var2.getPacketSize() + 1;
|
||||
|
||||
if (this.func_74454_a(var2, par1)) {
|
||||
var2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
return var2;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean func_74454_a(Packet par1Packet, boolean par2) {
|
||||
if (!par1Packet.isRealPacket()) {
|
||||
return false;
|
||||
} else {
|
||||
List var3 = par2 ? this.chunkDataPackets : this.dataPackets;
|
||||
Iterator var4 = var3.iterator();
|
||||
Packet var5;
|
||||
|
||||
do {
|
||||
if (!var4.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var5 = (Packet) var4.next();
|
||||
} while (var5.getPacketId() != par1Packet.getPacketId());
|
||||
|
||||
return par1Packet.containsSameEntityIDAs(var5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wakes reader and writer threads
|
||||
*/
|
||||
public void wakeThreads() {
|
||||
if (this.readThread != null) {
|
||||
this.readThread.interrupt();
|
||||
}
|
||||
|
||||
if (this.writeThread != null) {
|
||||
this.writeThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single packet from the input stream and adds it to the read queue. If
|
||||
* no packet is read, it shuts down the network.
|
||||
*/
|
||||
private boolean readPacket() {
|
||||
boolean var1 = false;
|
||||
|
||||
try {
|
||||
Packet var2 = Packet.readPacket(this.field_98215_i, this.socketInputStream,
|
||||
this.theNetHandler.isServerHandler(), this.networkSocket);
|
||||
|
||||
if (var2 != null) {
|
||||
if (var2 instanceof Packet252SharedKey && !this.isInputBeingDecrypted) {
|
||||
if (this.theNetHandler.isServerHandler()) {
|
||||
this.sharedKeyForEncryption = ((Packet252SharedKey) var2).getSharedKey(this.field_74463_A);
|
||||
}
|
||||
|
||||
this.decryptInputStream();
|
||||
}
|
||||
|
||||
int[] var10000 = field_74470_c;
|
||||
int var10001 = var2.getPacketId();
|
||||
var10000[var10001] += var2.getPacketSize() + 1;
|
||||
|
||||
if (!this.isServerTerminating) {
|
||||
if (var2.canProcessAsync() && this.theNetHandler.canProcessPacketsAsync()) {
|
||||
this.field_74490_x = 0;
|
||||
var2.processPacket(this.theNetHandler);
|
||||
} else {
|
||||
this.readPackets.add(var2);
|
||||
}
|
||||
}
|
||||
|
||||
var1 = true;
|
||||
} else {
|
||||
this.networkShutdown("disconnect.endOfStream", new Object[0]);
|
||||
}
|
||||
|
||||
return var1;
|
||||
} catch (Exception var3) {
|
||||
if (!this.isTerminating) {
|
||||
this.onNetworkError(var3);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to report network errors and causes a network shutdown.
|
||||
*/
|
||||
private void onNetworkError(Exception par1Exception) {
|
||||
par1Exception.printStackTrace();
|
||||
this.networkShutdown("disconnect.genericReason",
|
||||
new Object[] { "Internal exception: " + par1Exception.toString() });
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the network with the specified reason. Closes all streams and
|
||||
* sockets, spawns NetworkMasterThread to stop reading and writing threads.
|
||||
*/
|
||||
public void networkShutdown(String par1Str, Object... par2ArrayOfObj) {
|
||||
if (this.isRunning) {
|
||||
this.isTerminating = true;
|
||||
this.terminationReason = par1Str;
|
||||
this.field_74480_w = par2ArrayOfObj;
|
||||
this.isRunning = false;
|
||||
(new TcpMasterThread(this)).start();
|
||||
|
||||
try {
|
||||
this.socketInputStream.close();
|
||||
} catch (Throwable var6) {
|
||||
;
|
||||
}
|
||||
|
||||
try {
|
||||
this.socketOutputStream.close();
|
||||
} catch (Throwable var5) {
|
||||
;
|
||||
}
|
||||
|
||||
try {
|
||||
this.networkSocket.close();
|
||||
} catch (Throwable var4) {
|
||||
;
|
||||
}
|
||||
|
||||
this.socketInputStream = null;
|
||||
this.socketOutputStream = null;
|
||||
this.networkSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks timeouts and processes all pending read packets.
|
||||
*/
|
||||
public void processReadPackets() {
|
||||
if (this.sendQueueByteLength > 2097152) {
|
||||
this.networkShutdown("disconnect.overflow", new Object[0]);
|
||||
}
|
||||
|
||||
if (this.readPackets.isEmpty()) {
|
||||
if (this.field_74490_x++ == 1200) {
|
||||
this.networkShutdown("disconnect.timeout", new Object[0]);
|
||||
}
|
||||
} else {
|
||||
this.field_74490_x = 0;
|
||||
}
|
||||
|
||||
int var1 = 1000;
|
||||
|
||||
while (!this.readPackets.isEmpty() && var1-- >= 0) {
|
||||
Packet var2 = (Packet) this.readPackets.remove(0);
|
||||
var2.processPacket(this.theNetHandler);
|
||||
}
|
||||
|
||||
this.wakeThreads();
|
||||
|
||||
if (this.isTerminating && this.readPackets.isEmpty()) {
|
||||
this.theNetHandler.handleErrorMessage(this.terminationReason, this.field_74480_w);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the socket address of the remote side. Server-only.
|
||||
*/
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return this.remoteSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the server. (Only actually used on the server)
|
||||
*/
|
||||
public void serverShutdown() {
|
||||
if (!this.isServerTerminating) {
|
||||
this.wakeThreads();
|
||||
this.isServerTerminating = true;
|
||||
this.readThread.interrupt();
|
||||
(new TcpMonitorThread(this)).start();
|
||||
}
|
||||
}
|
||||
|
||||
private void decryptInputStream() throws IOException {
|
||||
this.isInputBeingDecrypted = true;
|
||||
InputStream var1 = this.networkSocket.getInputStream();
|
||||
this.socketInputStream = new DataInputStream(
|
||||
CryptManager.decryptInputStream(this.sharedKeyForEncryption, var1));
|
||||
}
|
||||
|
||||
/**
|
||||
* flushes the stream and replaces it with an encryptedOutputStream
|
||||
*/
|
||||
private void encryptOuputStream() throws IOException {
|
||||
this.socketOutputStream.flush();
|
||||
this.isOutputEncrypted = true;
|
||||
BufferedOutputStream var1 = new BufferedOutputStream(
|
||||
CryptManager.encryptOuputStream(this.sharedKeyForEncryption, this.networkSocket.getOutputStream()),
|
||||
5120);
|
||||
this.socketOutputStream = new DataOutputStream(var1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of chunk data packets waiting to be sent.
|
||||
*/
|
||||
public int getNumChunkDataPackets() {
|
||||
return this.chunkDataPackets.size();
|
||||
}
|
||||
|
||||
public Socket getSocket() {
|
||||
return this.networkSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the network is operational.
|
||||
*/
|
||||
static boolean isRunning(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.isRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the server terminating? Client side aways returns false.
|
||||
*/
|
||||
static boolean isServerTerminating(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.isServerTerminating;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static accessor to readPacket.
|
||||
*/
|
||||
static boolean readNetworkPacket(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.readPacket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Static accessor to sendPacket.
|
||||
*/
|
||||
static boolean sendNetworkPacket(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.sendPacket();
|
||||
}
|
||||
|
||||
static DataOutputStream getOutputStream(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.socketOutputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the Network manager is terminating.
|
||||
*/
|
||||
static boolean isTerminating(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.isTerminating;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the network manager an error
|
||||
*/
|
||||
static void sendError(TcpConnection par0TcpConnection, Exception par1Exception) {
|
||||
par0TcpConnection.onNetworkError(par1Exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the read thread.
|
||||
*/
|
||||
static Thread getReadThread(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.readThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the write thread.
|
||||
*/
|
||||
static Thread getWriteThread(TcpConnection par0TcpConnection) {
|
||||
return par0TcpConnection.writeThread;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user