io.gomint.proxprox.network.AbstractConnection.java Source code

Java tutorial

Introduction

Here is the source code for io.gomint.proxprox.network.AbstractConnection.java

Source

/*
 * Copyright (c) 2016, GoMint, BlackyPaw and geNAZt
 *
 * This code is licensed under the BSD license found in the
 * LICENSE file in the root directory of this source tree.
 */

package io.gomint.proxprox.network;

import io.gomint.jraknet.PacketBuffer;
import io.gomint.proxprox.ProxProxProxy;
import io.gomint.proxprox.api.network.Packet;
import io.gomint.server.jni.NativeCode;
import io.gomint.server.jni.zlib.JavaZLib;
import io.gomint.server.jni.zlib.NativeZLib;
import io.gomint.server.jni.zlib.ZLib;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import lombok.Getter;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.zip.DataFormatException;

/**
 * @author geNAZt
 * @version 1.0
 */
public abstract class AbstractConnection {

    private static final NativeCode<ZLib> ZLIB = new NativeCode<>("zlib", JavaZLib.class, NativeZLib.class);
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractConnection.class);

    static {
        // Load zlib native
        ZLIB.load();
    }

    @Getter
    protected ConnectionState state = ConnectionState.HANDSHAKE;
    @Getter
    protected EncryptionHandler encryptionHandler = null;
    @Getter
    protected PostProcessExecutor executor = null;
    private ZLib decompressor;

    protected void initDecompressor() {
        this.decompressor = ZLIB.newInstance();
        this.decompressor.init(false, false, 7);
    }

    /**
     * Setup the internal structures needed for the Connection
     */
    protected void setup() {
        this.executor = ProxProxProxy.getInstance().getProcessExecutorService().getExecutor();
    }

    /**
     * Handles compressed batch packets directly by decoding their payload.
     *
     * @param buffer The buffer containing the batch packet's data (except packet ID)
     * @return decompressed and decrypted data
     */
    byte[] handleBatchPacket(PacketBuffer buffer) {
        // Encrypted?
        byte[] input = new byte[buffer.getRemaining()];
        System.arraycopy(buffer.getBuffer(), buffer.getPosition(), input, 0, input.length);
        if (this.encryptionHandler != null) {
            input = this.encryptionHandler.isEncryptionFromServerEnabled()
                    ? this.encryptionHandler.decryptInputFromServer(input)
                    : this.encryptionHandler.decryptInputFromClient(input);
            if (input == null) {
                // Decryption error
                disconnect("Checksum of encrypted packet was wrong");
                return null;
            }
        }

        ByteBuf inBuf = PooledByteBufAllocator.DEFAULT.directBuffer(input.length);
        inBuf.writeBytes(input);

        ByteBuf outBuf = PooledByteBufAllocator.DEFAULT.directBuffer(8192); // We will write at least once so ensureWrite will realloc to 8192 so or so

        try {
            this.decompressor.process(inBuf, outBuf);
        } catch (DataFormatException e) {
            LOGGER.error("Failed to decompress batch packet", e);
            outBuf.release();
            return null;
        } finally {
            inBuf.release();
        }

        byte[] data = new byte[outBuf.readableBytes()];
        outBuf.readBytes(data);
        outBuf.release();
        return data;
    }

    /**
     * Little internal handler for packets
     *
     * @param buffer          The buffer which holds the packet
     */
    protected abstract void handlePacket(PacketBuffer buffer);

    public abstract void disconnect(String message);

    /**
     * Parses the specified JSON string and ensures it is a JSONObject.
     *
     * @param jwt The string to parse
     * @return The parsed JSON object on success
     * @throws ParseException Thrown if the given JSON string is invalid or does not start with a JSONObject
     */
    protected JSONObject parseJwtString(String jwt) throws ParseException {
        Object jsonParsed = new JSONParser().parse(jwt);
        if (jsonParsed instanceof JSONObject) {
            return (JSONObject) jsonParsed;
        } else {
            throw new ParseException(ParseException.ERROR_UNEXPECTED_TOKEN);
        }
    }

    public abstract void send(Packet packet);

    public void close() {
        if (this.state == ConnectionState.DISCONNECTED) {
            LOGGER.debug("Anonymous tried to close a already closed connection");
            return;
        }

        ProxProxProxy.getInstance().getProcessExecutorService().releaseExecutor(this.executor);
        this.executor = null;
        this.state = ConnectionState.DISCONNECTED;
    }

    protected enum ConnectionState {
        HANDSHAKE, CONNECTED, ENCRYPTED, DISCONNECTED
    }

}