2018-09-17 10:07:32 +03:00
|
|
|
package ru.gravit.launchserver.socket;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.math.BigInteger;
|
|
|
|
import java.net.Socket;
|
|
|
|
import java.net.SocketException;
|
|
|
|
|
|
|
|
import ru.gravit.launcher.Launcher;
|
2018-09-17 10:20:34 +03:00
|
|
|
import ru.gravit.utils.helper.IOHelper;
|
|
|
|
import ru.gravit.utils.helper.LogHelper;
|
|
|
|
import ru.gravit.utils.helper.SecurityHelper;
|
2018-09-17 10:07:32 +03:00
|
|
|
import ru.gravit.launcher.request.RequestException;
|
|
|
|
import ru.gravit.launcher.serialize.HInput;
|
|
|
|
import ru.gravit.launcher.serialize.HOutput;
|
|
|
|
import ru.gravit.launchserver.LaunchServer;
|
|
|
|
import ru.gravit.launchserver.manangers.SessionManager;
|
|
|
|
import ru.gravit.launchserver.response.Response;
|
|
|
|
|
|
|
|
public final class ResponseThread implements Runnable {
|
|
|
|
class Handshake {
|
|
|
|
int type;
|
|
|
|
long session;
|
|
|
|
|
|
|
|
public Handshake(int type, long session) {
|
|
|
|
this.type = type;
|
|
|
|
this.session = session;
|
|
|
|
}
|
|
|
|
}
|
2018-09-22 17:33:00 +03:00
|
|
|
|
2018-09-17 10:07:32 +03:00
|
|
|
private final LaunchServer server;
|
|
|
|
private final Socket socket;
|
|
|
|
|
|
|
|
private final SessionManager sessions;
|
|
|
|
|
|
|
|
public ResponseThread(LaunchServer server, long id, Socket socket, SessionManager sessionManager) throws SocketException {
|
|
|
|
this.server = server;
|
|
|
|
this.socket = socket;
|
|
|
|
sessions = sessionManager;
|
|
|
|
// Fix socket flags
|
|
|
|
IOHelper.setSocketFlags(socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
private Handshake readHandshake(HInput input, HOutput output) throws IOException {
|
|
|
|
boolean legacy = false;
|
|
|
|
long session = 0;
|
|
|
|
// Verify magic number
|
|
|
|
int magicNumber = input.readInt();
|
|
|
|
if (magicNumber != Launcher.PROTOCOL_MAGIC)
|
2018-09-22 17:33:00 +03:00
|
|
|
if (magicNumber == Launcher.PROTOCOL_MAGIC_LEGACY - 1) { // Previous launcher protocol
|
2018-09-17 10:07:32 +03:00
|
|
|
session = 0;
|
|
|
|
legacy = true;
|
2018-09-22 17:33:00 +03:00
|
|
|
} else if (magicNumber == Launcher.PROTOCOL_MAGIC_LEGACY - 2) { // Previous launcher protocol
|
2018-09-19 15:03:52 +03:00
|
|
|
session = 0;
|
|
|
|
legacy = true;
|
2018-09-22 17:33:00 +03:00
|
|
|
} else if (magicNumber == Launcher.PROTOCOL_MAGIC_LEGACY) {
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
} else
|
2018-09-22 17:33:00 +03:00
|
|
|
throw new IOException("Invalid Handshake");
|
2018-09-17 10:07:32 +03:00
|
|
|
// Verify key modulus
|
|
|
|
BigInteger keyModulus = input.readBigInteger(SecurityHelper.RSA_KEY_LENGTH + 1);
|
|
|
|
if (!legacy) {
|
|
|
|
session = input.readLong();
|
|
|
|
sessions.updateClient(session);
|
|
|
|
}
|
|
|
|
if (!keyModulus.equals(server.privateKey.getModulus())) {
|
|
|
|
output.writeBoolean(false);
|
|
|
|
throw new IOException(String.format("#%d Key modulus mismatch", session));
|
|
|
|
}
|
|
|
|
// Read request type
|
2018-09-22 17:33:00 +03:00
|
|
|
int type = input.readVarInt();
|
2018-09-17 10:07:32 +03:00
|
|
|
if (!server.serverSocketHandler.onHandshake(session, type)) {
|
|
|
|
output.writeBoolean(false);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Protocol successfully verified
|
|
|
|
output.writeBoolean(true);
|
|
|
|
output.flush();
|
|
|
|
return new Handshake(type, session);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void respond(Integer type, HInput input, HOutput output, long session, String ip) throws Exception {
|
|
|
|
if (server.serverSocketHandler.logConnections)
|
2018-09-22 17:33:00 +03:00
|
|
|
LogHelper.info("Connection #%d from %s", session, ip);
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
// Choose response based on type
|
|
|
|
Response response = Response.getResponse(type, server, session, input, output, ip);
|
|
|
|
|
|
|
|
// Reply
|
|
|
|
response.reply();
|
|
|
|
LogHelper.subDebug("#%d Replied", session);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
if (!server.serverSocketHandler.logConnections)
|
2018-09-22 17:33:00 +03:00
|
|
|
LogHelper.debug("Connection from %s", IOHelper.getIP(socket.getRemoteSocketAddress()));
|
2018-09-17 10:07:32 +03:00
|
|
|
|
|
|
|
// Process connection
|
|
|
|
boolean cancelled = false;
|
|
|
|
Exception savedError = null;
|
|
|
|
try (HInput input = new HInput(socket.getInputStream());
|
|
|
|
HOutput output = new HOutput(socket.getOutputStream())) {
|
|
|
|
Handshake handshake = readHandshake(input, output);
|
|
|
|
if (handshake == null) { // Not accepted
|
|
|
|
cancelled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start response
|
|
|
|
try {
|
|
|
|
respond(handshake.type, input, output, handshake.session, IOHelper.getIP(socket.getRemoteSocketAddress()));
|
|
|
|
} catch (RequestException e) {
|
|
|
|
LogHelper.subDebug(String.format("#%d Request error: %s", handshake.session, e.getMessage()));
|
|
|
|
output.writeString(e.getMessage(), 0);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
savedError = e;
|
|
|
|
LogHelper.error(e);
|
|
|
|
} finally {
|
|
|
|
IOHelper.close(socket);
|
|
|
|
if (!cancelled)
|
2018-09-22 17:33:00 +03:00
|
|
|
server.serverSocketHandler.onDisconnect(savedError);
|
2018-09-17 10:07:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|