
public class ClientListener implements Runnable {
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private boolean connected;
private static final String RC4_OUTGOING_KEY = "c79332b197f92ba85ed281a023";
private static final String RC4_INCOMING_KEY = "6a39570cc9de4ec71d64821894";
private RC4 inRC4;
private RC4 outRC4;
public ClientListener(Socket socket) {
this.socket = socket;
}
@override
public void run() {
try {
System.out.println(" *** Connection from: " + this.socket.getInetAddress().getHostName() + " ***");
this.in = new DataInputStream(this.socket.getInputStream());
this.out = new DataOutputStream(this.socket.getOutputStream());
this.connected = true;
int bufferSize = -1;
byte bufferId = -1;
long lastData = System.currentTimeMillis();
this.inRC4 = new RC4(RC4_INCOMING_KEY);
this.outRC4 = new RC4(RC4_OUTGOING_KEY);
while (this.connected) {
try {
if (lastData > System.currentTimeMillis() + (1000 * 15)) this.disconnect(); // Exit loop after data timeout
if (this.in.available() >= 5 && bufferSize == -1) {
lastData = System.currentTimeMillis();
bufferSize = this.in.readInt() - 5;
bufferId = this.in.readByte();
} else if (this.in.available() >= bufferSize && bufferSize != -1) {
lastData = System.currentTimeMillis();
PacketType type = PacketType.fromId(bufferId);
byte[] buf = new byte[bufferSize];
this.in.readFully(buf);
bufferSize = -1;
if (type == PacketType.UNKNOWN) continue; // Dont bother if the packet is of an unknown type
buf = this.inRC4.cypher(buf);
ByteArrayInputStream bis = new ByteArrayInputStream(buf);
DataInputStream dis = new DataInputStream(bis);
try {
Packet p = type.create();
p.read(dis);
this.invokeOnPacket(p);
} catch (IOException e) {
e.printStackTrace();
} finally {
bis.close();
dis.close();
}
}
Thread.sleep(100); // Only check socket for connections 10 times / second to prevent cpu hogging
} catch (Exception e) {
e.printStackTrace(); // debug
break;
}
}
} catch (Exception e) {
e.printStackTrace(); // debug
this.disconnect();
}
this.disconnect();
}
private void sendPacket(Packet p) {
if (!this.socket.isConnected()) return;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
try {
p.write(out);
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
try {
baos.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] buf = this.outRC4.cypher(baos.toByteArray());
try {
this.out.writeInt(buf.length + 5);
this.out.writeByte(p.getType().id);
this.out.write(buf);
} catch (IOException e) {
e.printStackTrace();
}
}
private void invokeOnPacket(Packet p) {}
private void disconnect() {
if (!this.connected) return;
try {
System.out.println(" *** Disconnected from: " + this.socket.getInetAddress().getHostName() + " ***");
this.connected = false;
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}