Newer
Older
KeeperJerry_Launcher / LaunchServer / source / response / ResponseThread.java
@sashok724 sashok724 on 30 Oct 2015 4 KB Команда logConnections
package launchserver.response;

import java.io.IOException;
import java.math.BigInteger;
import java.net.Socket;
import java.net.SocketException;

import launcher.Launcher;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
import launcher.helper.SecurityHelper;
import launcher.helper.VerifyHelper;
import launcher.request.Request;
import launcher.request.RequestException;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launchserver.LaunchServer;
import launchserver.response.auth.AuthResponse;
import launchserver.response.auth.CheckServerResponse;
import launchserver.response.auth.JoinServerResponse;
import launchserver.response.profile.BatchProfileByUsernameResponse;
import launchserver.response.profile.ProfileByUUIDResponse;
import launchserver.response.profile.ProfileByUsernameResponse;
import launchserver.response.update.LauncherResponse;
import launchserver.response.update.UpdateListResponse;
import launchserver.response.update.UpdateResponse;

public final class ResponseThread implements Runnable {
	private final LaunchServer server;
	private final long id;
	private final Socket socket;

	public ResponseThread(LaunchServer server, long id, Socket socket) throws SocketException {
		this.server = server;
		this.id = id;
		this.socket = socket;

		// Fix socket flags
		IOHelper.setSocketFlags(socket);
	}

	@Override
	public void run() {
		boolean cancelled = false;
		Exception savedError = null;
		if (!server.serverSocketHandler.logConnections) {
			LogHelper.debug("Connection #%d from %s", id, IOHelper.getIP(socket.getRemoteSocketAddress()));
		}

		// Process connection
		try (HInput input = new HInput(socket.getInputStream());
			 HOutput output = new HOutput(socket.getOutputStream())) {
			Request.Type type = readHandshake(input, output);
			if (type == null) { // Not accepted
				cancelled = true;
				return;
			}

			// Start response
			try {
				respond(type, input, output);
			} catch (RequestException e) {
				LogHelper.subDebug(String.format("#%d Request error: %s", id, e.getMessage()));
				output.writeString(e.getMessage(), 0);
			}
		} catch (Exception e) {
			savedError = e;
			LogHelper.error(e);
		} finally {
			IOHelper.close(socket);
			if (!cancelled) {
				server.serverSocketHandler.onDisconnect(id, savedError);
			}
		}
	}

	private Request.Type readHandshake(HInput input, HOutput output) throws IOException {
		// Verify magic number
		int magicNumber = input.readInt();
		if (magicNumber != Launcher.PROTOCOL_MAGIC) {
			output.writeBoolean(false);
			throw new IOException(String.format("#%d Protocol magic mismatch", id));
		}

		// Verify key modulus
		BigInteger keyModulus = input.readBigInteger(SecurityHelper.RSA_KEY_LENGTH + 1);
		if (!keyModulus.equals(server.privateKey.getModulus())) {
			output.writeBoolean(false);
			throw new IOException(String.format("#%d Key modulus mismatch", id));
		}

		// Read request type
		Request.Type type = Request.Type.read(input);
		if (!server.serverSocketHandler.onHandshake(id, type)) {
			output.writeBoolean(false);
			return null;
		}

		// Protocol successfully verified
		output.writeBoolean(true);
		output.flush();
		return type;
	}

	private void respond(Request.Type type, HInput input, HOutput output) throws Exception {
		if (server.serverSocketHandler.logConnections) {
			LogHelper.info("Connection %d from %s: %s", id, IOHelper.getIP(socket.getRemoteSocketAddress()), type.name());
		} else {
			LogHelper.subDebug("#%d Type: %s", id, type.name());
		}

		// Choose response based on type
		Response response;
		switch (type) {
			case PING:
				response = new PingResponse(server, id, input, output);
				break;
			case AUTH:
				response = new AuthResponse(server, id, input, output);
				break;
			case JOIN_SERVER:
				response = new JoinServerResponse(server, id, input, output);
				break;
			case CHECK_SERVER:
				response = new CheckServerResponse(server, id, input, output);
				break;
			case LAUNCHER:
				response = new LauncherResponse(server, id, input, output);
				break;
			case UPDATE:
				response = new UpdateResponse(server, id, input, output);
				break;
			case UPDATE_LIST:
				response = new UpdateListResponse(server, id, input, output);
				break;
			case PROFILE_BY_USERNAME:
				response = new ProfileByUsernameResponse(server, id, input, output);
				break;
			case PROFILE_BY_UUID:
				response = new ProfileByUUIDResponse(server, id, input, output);
				break;
			case BATCH_PROFILE_BY_USERNAME:
				response = new BatchProfileByUsernameResponse(server, id, input, output);
				break;
			case CUSTOM:
				String name = VerifyHelper.verifyIDName(input.readASCII(255));
				response = server.serverSocketHandler.newCustomResponse(name, id, input, output);
				break;
			default:
				throw new AssertionError("Unsupported request type: " + type.name());
		}

		// Reply
		response.reply();
		LogHelper.subDebug("#%d Replied", id);
	}
}