org.virtue.network.protocol.handshake.HandshakeDecoder.java Source code

Java tutorial

Introduction

Here is the source code for org.virtue.network.protocol.handshake.HandshakeDecoder.java

Source

/**
 * Copyright (c) 2014 Virtue Studios
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.virtue.network.protocol.handshake;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.virtue.Constants;
import org.virtue.network.protocol.creation.CreationDecoder;
import org.virtue.network.protocol.login.LoginDecoder;
import org.virtue.network.protocol.login.LoginEncoder;
import org.virtue.network.protocol.message.HandshakeMessage;
import org.virtue.network.protocol.ondemand.OnDemandDecoder;
import org.virtue.network.protocol.ondemand.OnDemandEncoder;
import org.virtue.network.protocol.ondemand.OnDemandXorEncoder;
import org.virtue.network.protocol.social.SocialNetworkDecoder;
import org.virtue.utility.BufferUtility;

/**
 * @author Im Frizzy <skype:kfriz1998>
 * @since Aug 8, 2014
 */
public class HandshakeDecoder extends ByteToMessageDecoder {

    /**
     * The {@link Logger} instance
     */
    private static Logger logger = LoggerFactory.getLogger(HandshakeDecoder.class);

    /* (non-Javadoc)
     * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
        if (buf.isReadable()) {
            HandshakeMessage type = new HandshakeMessage(buf.readUnsignedByte());
            if (type.getType() == null) {
                ctx.close();//Disconnect the player if they have an invalid handshake code.
                return;
            }
            switch (type.getType()) {
            case HANDSHAKE_LOGIN:
                ensureResponse(ctx);
                ctx.pipeline().replace("decoder", "decoder", new LoginDecoder());
                ctx.pipeline().addBefore("decoder", "encoder", new LoginEncoder());
                break;
            case HANDSHAKE_ONDEMAND:
                ensureResponse(ctx, buf);
                ctx.pipeline().replace("decoder", "decoder", new OnDemandDecoder());
                ctx.pipeline().addAfter("decoder", "xor-encoder", new OnDemandXorEncoder());
                ctx.pipeline().addAfter("xor-encoder", "encoder", new OnDemandEncoder());
                break;
            case HANDHSHAKE_CREATION:
                ctx.pipeline().replace("decoder", "decoder", new CreationDecoder());
                break;
            case HANDSHAKE_SOCIAL_LOGIN:
                ensureResponse(ctx);
                ctx.pipeline().replace("decoder", "decoder", new SocialNetworkDecoder());
                break;
            default:
                break;
            }
            //ctx.pipeline().remove(HandshakeDecoder.class);
            //if (buf.isReadable()) {
            //out.add(new Object[] { type, buf.readBytes(buf.readableBytes()) });
            //} else {
            out.add(type);
            //}
        }
    }

    private void ensureResponse(ChannelHandlerContext ctx) {
        ByteBuf buffer = Unpooled.buffer(1);
        buffer.writeByte(0);
        ctx.channel().writeAndFlush(buffer);
    }

    private void ensureResponse(ChannelHandlerContext ctx, ByteBuf buf) {
        if (buf.readableBytes() < 6) {
            return;
        }

        ByteBuf buffer = Unpooled.buffer();

        int length = buf.readUnsignedByte();
        if (buf.readableBytes() >= length) {
            int major = buf.readInt();
            int minor = buf.readInt();
            String token = BufferUtility.readString(buf);
            int languageId = buf.readByte();//Language ID
            if (languageId != 0) {
                logger.warn("Bad connection: Invalid language (sent: " + languageId + ", expected: 0)");
                buffer.writeByte(6);
            } else if (major != Constants.FRAME_MAJOR && minor != Constants.FRAME_MINOR) {
                logger.warn("Bad connection: Invalid major-minor version (sent: " + major + "_" + minor
                        + ", expected: " + Constants.FRAME_MAJOR + "_" + Constants.FRAME_MINOR + ")");
                buffer.writeByte(6);
            } else {
                if (!token.equals(Constants.getJs5Token())) {
                    logger.warn("Bad connection: Invalid server token (sent: " + token + ", expected: "
                            + Constants.getJs5Token() + ")");
                    buffer.writeByte(6);
                } else {
                    buffer.writeByte(0);
                    for (int i = 0; i < Constants.ONDEMAND_DELTA.length; i++) {
                        buffer.writeInt(Constants.ONDEMAND_DELTA[i]);
                    }
                }
            }
        }
        ctx.channel().writeAndFlush(buffer);
    }

}