com.github.koraktor.steamcondenser.servers.packets.SteamPacketFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.github.koraktor.steamcondenser.servers.packets.SteamPacketFactory.java

Source

/**
 * This code is free software; you can redistribute it and/or modify it under
 * the terms of the new BSD License.
 *
 * Copyright (c) 2008-2013, Sebastian Staudt
 */

package com.github.koraktor.steamcondenser.servers.packets;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.zip.CRC32;

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;

import com.github.koraktor.steamcondenser.Helper;
import com.github.koraktor.steamcondenser.exceptions.PacketFormatException;
import com.github.koraktor.steamcondenser.exceptions.SteamCondenserException;
import com.github.koraktor.steamcondenser.servers.packets.rcon.RCONGoldSrcResponsePacket;

/**
 * This module provides functionality to handle raw packet data, including data
 * split into several UDP / TCP packets and BZIP2 compressed data. It's the
 * main utility to transform data bytes into packet objects.
 *
 * @author Sebastian Staudt
 * @see SteamPacket
 */
public abstract class SteamPacketFactory {

    /**
     * Creates a new packet object based on the header byte of the given raw
     * data
     *
     * @param rawData The raw data of the packet
     * @throws PacketFormatException if the packet header is not recognized
     * @return The packet object generated from the packet data
     */
    public static SteamPacket getPacketFromData(byte[] rawData) throws PacketFormatException {
        byte header = rawData[0];
        byte[] data = new byte[rawData.length - 1];
        System.arraycopy(rawData, 1, data, 0, rawData.length - 1);

        switch (header) {
        case SteamPacket.A2S_INFO_HEADER:
            return new A2S_INFO_Packet();

        case SteamPacket.S2A_INFO_DETAILED_HEADER:
            return new S2A_INFO_DETAILED_Packet(data);

        case SteamPacket.S2A_INFO2_HEADER:
            return new S2A_INFO2_Packet(data);

        case SteamPacket.A2S_PLAYER_HEADER:
            return new A2S_PLAYER_Packet(Helper.integerFromByteArray(data));

        case SteamPacket.S2A_PLAYER_HEADER:
            return new S2A_PLAYER_Packet(data);

        case SteamPacket.A2S_RULES_HEADER:
            return new A2S_RULES_Packet(Helper.integerFromByteArray(data));

        case SteamPacket.S2A_RULES_HEADER:
            return new S2A_RULES_Packet(data);

        case SteamPacket.A2S_SERVERQUERY_GETCHALLENGE_HEADER:
            return new A2S_SERVERQUERY_GETCHALLENGE_Packet();

        case SteamPacket.S2C_CHALLENGE_HEADER:
            return new S2C_CHALLENGE_Packet(data);

        case SteamPacket.M2A_SERVER_BATCH_HEADER:
            return new M2A_SERVER_BATCH_Paket(data);

        case SteamPacket.RCON_GOLDSRC_CHALLENGE_HEADER:
        case SteamPacket.RCON_GOLDSRC_NO_CHALLENGE_HEADER:
        case SteamPacket.RCON_GOLDSRC_RESPONSE_HEADER:
            return new RCONGoldSrcResponsePacket(data);

        default:
            throw new PacketFormatException(
                    "Unknown packet with header 0x" + Integer.toHexString(header) + " received.");
        }
    }

    /**
     * Reassembles the data of a split packet into a single packet object
     *
     * @param splitPackets An array of packet data
     * @throws SteamCondenserException if decompressing the packet data fails
     * @throws PacketFormatException if the calculated CRC32 checksum does not
     *         match the expected value
     * @return SteamPacket The reassembled packet
     * @see SteamPacketFactory#getPacketFromData
     */
    public static SteamPacket reassemblePacket(ArrayList<byte[]> splitPackets) throws SteamCondenserException {
        return SteamPacketFactory.reassemblePacket(splitPackets, false, 0, 0);
    }

    /**
     * Reassembles the data of a split and/or compressed packet into a single
     * packet object
     *
     * @param splitPackets An array of packet data
     * @param isCompressed whether the data of this packet is compressed
     * @param uncompressedSize The size of the decompressed packet data
     * @param packetChecksum The CRC32 checksum of the decompressed
     *        packet data
     * @throws SteamCondenserException if decompressing the packet data fails
     * @throws PacketFormatException if the calculated CRC32 checksum does not
     *         match the expected value
     * @return SteamPacket The reassembled packet
     * @see SteamPacketFactory#getPacketFromData
     */
    public static SteamPacket reassemblePacket(ArrayList<byte[]> splitPackets, boolean isCompressed,
            int uncompressedSize, int packetChecksum) throws SteamCondenserException {
        byte[] packetData, tmpData;
        packetData = new byte[0];

        for (byte[] splitPacket : splitPackets) {
            tmpData = packetData;
            packetData = new byte[tmpData.length + splitPacket.length];
            System.arraycopy(tmpData, 0, packetData, 0, tmpData.length);
            System.arraycopy(splitPacket, 0, packetData, tmpData.length, splitPacket.length);
        }

        if (isCompressed) {
            try {
                ByteArrayInputStream stream = new ByteArrayInputStream(packetData);
                stream.read();
                stream.read();
                BZip2CompressorInputStream bzip2 = new BZip2CompressorInputStream(stream);
                byte[] uncompressedPacketData = new byte[uncompressedSize];
                bzip2.read(uncompressedPacketData, 0, uncompressedSize);

                CRC32 crc32 = new CRC32();
                crc32.update(uncompressedPacketData);
                int crc32checksum = (int) crc32.getValue();

                if (crc32checksum != packetChecksum) {
                    throw new PacketFormatException("CRC32 checksum mismatch of uncompressed packet data.");
                }
                packetData = uncompressedPacketData;
            } catch (IOException e) {
                throw new SteamCondenserException(e.getMessage(), e);
            }
        }

        tmpData = packetData;
        packetData = new byte[tmpData.length - 4];
        System.arraycopy(tmpData, 4, packetData, 0, tmpData.length - 4);

        return SteamPacketFactory.getPacketFromData(packetData);
    }
}