Path: blob/main/sp-server/src_aux/TcpConnection.java
8641 views
package net.minecraft.src;12import java.io.BufferedOutputStream;3import java.io.DataInputStream;4import java.io.DataOutputStream;5import java.io.IOException;6import java.io.InputStream;7import java.net.Socket;8import java.net.SocketAddress;9import java.net.SocketException;10import java.security.PrivateKey;11import java.util.ArrayList;12import java.util.Collections;13import java.util.Iterator;14import java.util.List;15import java.util.concurrent.atomic.AtomicInteger;16import javax.crypto.SecretKey;1718public class TcpConnection implements INetworkManager {19public static AtomicInteger field_74471_a = new AtomicInteger();20public static AtomicInteger field_74469_b = new AtomicInteger();2122/** The object used for synchronization on the send queue. */23private final Object sendQueueLock = new Object();24private final ILogAgent field_98215_i;2526/** The socket used by this network manager. */27private Socket networkSocket;2829/** The InetSocketAddress of the remote endpoint */30private final SocketAddress remoteSocketAddress;3132/** The input stream connected to the socket. */33private volatile DataInputStream socketInputStream;3435/** The output stream connected to the socket. */36private volatile DataOutputStream socketOutputStream;3738/** Whether the network is currently operational. */39private volatile boolean isRunning = true;4041/**42* Whether this network manager is currently terminating (and should ignore43* further errors).44*/45private volatile boolean isTerminating = false;4647/**48* Linked list of packets that have been read and are awaiting processing.49*/50private List readPackets = Collections.synchronizedList(new ArrayList());5152/** Linked list of packets awaiting sending. */53private List dataPackets = Collections.synchronizedList(new ArrayList());5455/** Linked list of packets with chunk data that are awaiting sending. */56private List chunkDataPackets = Collections.synchronizedList(new ArrayList());5758/** A reference to the NetHandler object. */59private NetHandler theNetHandler;6061/**62* Whether this server is currently terminating. If this is a client, this is63* always false.64*/65private boolean isServerTerminating = false;6667/** The thread used for writing. */68private Thread writeThread;6970/** The thread used for reading. */71private Thread readThread;7273/** A String indicating why the network has shutdown. */74private String terminationReason = "";75private Object[] field_74480_w;76private int field_74490_x = 0;7778/**79* The length in bytes of the packets in both send queues (data and chunkData).80*/81private int sendQueueByteLength = 0;82public static int[] field_74470_c = new int[256];83public static int[] field_74467_d = new int[256];84public int field_74468_e = 0;85boolean isInputBeingDecrypted = false;86boolean isOutputEncrypted = false;87private SecretKey sharedKeyForEncryption = null;88private PrivateKey field_74463_A = null;8990/**91* Delay for sending pending chunk data packets (as opposed to pending non-chunk92* data packets)93*/94private int chunkDataPacketsDelay = 50;9596public TcpConnection(ILogAgent par1ILogAgent, Socket par2Socket, String par3Str, NetHandler par4NetHandler,97PrivateKey par5PrivateKey) throws IOException {98this.field_74463_A = par5PrivateKey;99this.networkSocket = par2Socket;100this.field_98215_i = par1ILogAgent;101this.remoteSocketAddress = par2Socket.getRemoteSocketAddress();102this.theNetHandler = par4NetHandler;103104try {105par2Socket.setSoTimeout(30000);106par2Socket.setTrafficClass(24);107} catch (SocketException var7) {108System.err.println(var7.getMessage());109}110111this.socketInputStream = new DataInputStream(par2Socket.getInputStream());112this.socketOutputStream = new DataOutputStream(new BufferedOutputStream(par2Socket.getOutputStream(), 5120));113this.readThread = new TcpReaderThread(this, par3Str + " read thread");114this.writeThread = new TcpWriterThread(this, par3Str + " write thread");115this.readThread.start();116this.writeThread.start();117}118119/**120* Sets the NetHandler for this NetworkManager. Server-only.121*/122public void setNetHandler(NetHandler par1NetHandler) {123this.theNetHandler = par1NetHandler;124}125126/**127* Adds the packet to the correct send queue (chunk data packets go to a128* separate queue).129*/130public void addToSendQueue(Packet par1Packet) {131if (!this.isServerTerminating) {132Object var2 = this.sendQueueLock;133134synchronized (this.sendQueueLock) {135this.sendQueueByteLength += par1Packet.getPacketSize() + 1;136this.dataPackets.add(par1Packet);137}138}139}140141/**142* Sends a data packet if there is one to send, or sends a chunk data packet if143* there is one and the counter is up, or does nothing.144*/145private boolean sendPacket() {146boolean var1 = false;147148try {149int[] var10000;150int var10001;151Packet var2;152153if (this.field_74468_e == 0 || !this.dataPackets.isEmpty() && System.currentTimeMillis()154- ((Packet) this.dataPackets.get(0)).creationTimeMillis >= (long) this.field_74468_e) {155var2 = this.func_74460_a(false);156157if (var2 != null) {158Packet.writePacket(var2, this.socketOutputStream);159160if (var2 instanceof Packet252SharedKey && !this.isOutputEncrypted) {161if (!this.theNetHandler.isServerHandler()) {162this.sharedKeyForEncryption = ((Packet252SharedKey) var2).getSharedKey();163}164165this.encryptOuputStream();166}167168var10000 = field_74467_d;169var10001 = var2.getPacketId();170var10000[var10001] += var2.getPacketSize() + 1;171var1 = true;172}173}174175if (this.chunkDataPacketsDelay-- <= 0 && (this.field_74468_e == 0176|| !this.chunkDataPackets.isEmpty() && System.currentTimeMillis() - ((Packet) this.chunkDataPackets177.get(0)).creationTimeMillis >= (long) this.field_74468_e)) {178var2 = this.func_74460_a(true);179180if (var2 != null) {181Packet.writePacket(var2, this.socketOutputStream);182var10000 = field_74467_d;183var10001 = var2.getPacketId();184var10000[var10001] += var2.getPacketSize() + 1;185this.chunkDataPacketsDelay = 0;186var1 = true;187}188}189190return var1;191} catch (Exception var3) {192if (!this.isTerminating) {193this.onNetworkError(var3);194}195196return false;197}198}199200private Packet func_74460_a(boolean par1) {201Packet var2 = null;202List var3 = par1 ? this.chunkDataPackets : this.dataPackets;203Object var4 = this.sendQueueLock;204205synchronized (this.sendQueueLock) {206while (!var3.isEmpty() && var2 == null) {207var2 = (Packet) var3.remove(0);208this.sendQueueByteLength -= var2.getPacketSize() + 1;209210if (this.func_74454_a(var2, par1)) {211var2 = null;212}213}214215return var2;216}217}218219private boolean func_74454_a(Packet par1Packet, boolean par2) {220if (!par1Packet.isRealPacket()) {221return false;222} else {223List var3 = par2 ? this.chunkDataPackets : this.dataPackets;224Iterator var4 = var3.iterator();225Packet var5;226227do {228if (!var4.hasNext()) {229return false;230}231232var5 = (Packet) var4.next();233} while (var5.getPacketId() != par1Packet.getPacketId());234235return par1Packet.containsSameEntityIDAs(var5);236}237}238239/**240* Wakes reader and writer threads241*/242public void wakeThreads() {243if (this.readThread != null) {244this.readThread.interrupt();245}246247if (this.writeThread != null) {248this.writeThread.interrupt();249}250}251252/**253* Reads a single packet from the input stream and adds it to the read queue. If254* no packet is read, it shuts down the network.255*/256private boolean readPacket() {257boolean var1 = false;258259try {260Packet var2 = Packet.readPacket(this.field_98215_i, this.socketInputStream,261this.theNetHandler.isServerHandler(), this.networkSocket);262263if (var2 != null) {264if (var2 instanceof Packet252SharedKey && !this.isInputBeingDecrypted) {265if (this.theNetHandler.isServerHandler()) {266this.sharedKeyForEncryption = ((Packet252SharedKey) var2).getSharedKey(this.field_74463_A);267}268269this.decryptInputStream();270}271272int[] var10000 = field_74470_c;273int var10001 = var2.getPacketId();274var10000[var10001] += var2.getPacketSize() + 1;275276if (!this.isServerTerminating) {277if (var2.canProcessAsync() && this.theNetHandler.canProcessPacketsAsync()) {278this.field_74490_x = 0;279var2.processPacket(this.theNetHandler);280} else {281this.readPackets.add(var2);282}283}284285var1 = true;286} else {287this.networkShutdown("disconnect.endOfStream", new Object[0]);288}289290return var1;291} catch (Exception var3) {292if (!this.isTerminating) {293this.onNetworkError(var3);294}295296return false;297}298}299300/**301* Used to report network errors and causes a network shutdown.302*/303private void onNetworkError(Exception par1Exception) {304par1Exception.printStackTrace();305this.networkShutdown("disconnect.genericReason",306new Object[] { "Internal exception: " + par1Exception.toString() });307}308309/**310* Shuts down the network with the specified reason. Closes all streams and311* sockets, spawns NetworkMasterThread to stop reading and writing threads.312*/313public void networkShutdown(String par1Str, Object... par2ArrayOfObj) {314if (this.isRunning) {315this.isTerminating = true;316this.terminationReason = par1Str;317this.field_74480_w = par2ArrayOfObj;318this.isRunning = false;319(new TcpMasterThread(this)).start();320321try {322this.socketInputStream.close();323} catch (Throwable var6) {324;325}326327try {328this.socketOutputStream.close();329} catch (Throwable var5) {330;331}332333try {334this.networkSocket.close();335} catch (Throwable var4) {336;337}338339this.socketInputStream = null;340this.socketOutputStream = null;341this.networkSocket = null;342}343}344345/**346* Checks timeouts and processes all pending read packets.347*/348public void processReadPackets() {349if (this.sendQueueByteLength > 2097152) {350this.networkShutdown("disconnect.overflow", new Object[0]);351}352353if (this.readPackets.isEmpty()) {354if (this.field_74490_x++ == 1200) {355this.networkShutdown("disconnect.timeout", new Object[0]);356}357} else {358this.field_74490_x = 0;359}360361int var1 = 1000;362363while (!this.readPackets.isEmpty() && var1-- >= 0) {364Packet var2 = (Packet) this.readPackets.remove(0);365var2.processPacket(this.theNetHandler);366}367368this.wakeThreads();369370if (this.isTerminating && this.readPackets.isEmpty()) {371this.theNetHandler.handleErrorMessage(this.terminationReason, this.field_74480_w);372}373}374375/**376* Returns the socket address of the remote side. Server-only.377*/378public SocketAddress getRemoteAddress() {379return this.remoteSocketAddress;380}381382/**383* Shuts down the server. (Only actually used on the server)384*/385public void serverShutdown() {386if (!this.isServerTerminating) {387this.wakeThreads();388this.isServerTerminating = true;389this.readThread.interrupt();390(new TcpMonitorThread(this)).start();391}392}393394private void decryptInputStream() throws IOException {395this.isInputBeingDecrypted = true;396InputStream var1 = this.networkSocket.getInputStream();397this.socketInputStream = new DataInputStream(398CryptManager.decryptInputStream(this.sharedKeyForEncryption, var1));399}400401/**402* flushes the stream and replaces it with an encryptedOutputStream403*/404private void encryptOuputStream() throws IOException {405this.socketOutputStream.flush();406this.isOutputEncrypted = true;407BufferedOutputStream var1 = new BufferedOutputStream(408CryptManager.encryptOuputStream(this.sharedKeyForEncryption, this.networkSocket.getOutputStream()),4095120);410this.socketOutputStream = new DataOutputStream(var1);411}412413/**414* Returns the number of chunk data packets waiting to be sent.415*/416public int getNumChunkDataPackets() {417return this.chunkDataPackets.size();418}419420public Socket getSocket() {421return this.networkSocket;422}423424/**425* Whether the network is operational.426*/427static boolean isRunning(TcpConnection par0TcpConnection) {428return par0TcpConnection.isRunning;429}430431/**432* Is the server terminating? Client side aways returns false.433*/434static boolean isServerTerminating(TcpConnection par0TcpConnection) {435return par0TcpConnection.isServerTerminating;436}437438/**439* Static accessor to readPacket.440*/441static boolean readNetworkPacket(TcpConnection par0TcpConnection) {442return par0TcpConnection.readPacket();443}444445/**446* Static accessor to sendPacket.447*/448static boolean sendNetworkPacket(TcpConnection par0TcpConnection) {449return par0TcpConnection.sendPacket();450}451452static DataOutputStream getOutputStream(TcpConnection par0TcpConnection) {453return par0TcpConnection.socketOutputStream;454}455456/**457* Gets whether the Network manager is terminating.458*/459static boolean isTerminating(TcpConnection par0TcpConnection) {460return par0TcpConnection.isTerminating;461}462463/**464* Sends the network manager an error465*/466static void sendError(TcpConnection par0TcpConnection, Exception par1Exception) {467par0TcpConnection.onNetworkError(par1Exception);468}469470/**471* Returns the read thread.472*/473static Thread getReadThread(TcpConnection par0TcpConnection) {474return par0TcpConnection.readThread;475}476477/**478* Returns the write thread.479*/480static Thread getWriteThread(TcpConnection par0TcpConnection) {481return par0TcpConnection.writeThread;482}483}484485486