diff --git a/src/org/apollo/net/codec/game/GamePacketDecoder.java b/src/org/apollo/net/codec/game/GamePacketDecoder.java index 5434ce1e..947cd87f 100644 --- a/src/org/apollo/net/codec/game/GamePacketDecoder.java +++ b/src/org/apollo/net/codec/game/GamePacketDecoder.java @@ -4,7 +4,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import java.io.IOException; import java.util.List; import net.burtleburtle.bob.rand.IsaacRandom; @@ -61,7 +60,7 @@ public final class GamePacketDecoder extends StatefulFrameDecoder out, GameDecoderState state) throws IOException { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out, GameDecoderState state) { switch (state) { case GAME_OPCODE: decodeOpcode(in, out); @@ -96,9 +95,8 @@ public final class GamePacketDecoder extends StatefulFrameDecoder out) throws IOException { + private void decodeOpcode(ByteBuf buffer, List out) { if (buffer.isReadable()) { int encryptedOpcode = buffer.readUnsignedByte(); opcode = encryptedOpcode - random.nextInt() & 0xFF; @@ -121,7 +119,7 @@ public final class GamePacketDecoder extends StatefulFrameDecoder /** * The secure random number generator. */ - private static final SecureRandom random = new SecureRandom(); + private static final SecureRandom RANDOM = new SecureRandom(); /** * The login packet length. @@ -54,11 +54,11 @@ public final class LoginDecoder extends StatefulFrameDecoder * Creates the login decoder with the default initial state. */ public LoginDecoder() { - super(LoginDecoderState.LOGIN_HANDSHAKE, true); + super(LoginDecoderState.LOGIN_HANDSHAKE); } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out, LoginDecoderState state) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out, LoginDecoderState state) { switch (state) { case LOGIN_HANDSHAKE: decodeHandshake(ctx, in, out); @@ -70,7 +70,7 @@ public final class LoginDecoder extends StatefulFrameDecoder decodePayload(ctx, in, out); break; default: - throw new IllegalStateException("Invalid login decoder state."); + throw new IllegalStateException("Invalid login decoder state: " + state); } } @@ -84,7 +84,7 @@ public final class LoginDecoder extends StatefulFrameDecoder private void decodeHandshake(ChannelHandlerContext ctx, ByteBuf buffer, List out) { if (buffer.isReadable()) { usernameHash = buffer.readUnsignedByte(); - serverSeed = random.nextLong(); + serverSeed = RANDOM.nextLong(); ByteBuf response = ctx.alloc().buffer(17); response.writeByte(LoginConstants.STATUS_EXCHANGE_DATA); @@ -102,14 +102,14 @@ public final class LoginDecoder extends StatefulFrameDecoder * @param ctx The channel handler context. * @param buffer The buffer. * @param out The {@link List} of objects to pass forward through the pipeline. - * @throws IOException If the login type sent by the client is invalid. */ - private void decodeHeader(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws IOException { + private void decodeHeader(ChannelHandlerContext ctx, ByteBuf buffer, List out) { if (buffer.readableBytes() >= 2) { int loginType = buffer.readUnsignedByte(); if (loginType != LoginConstants.TYPE_STANDARD && loginType != LoginConstants.TYPE_RECONNECTION) { - throw new IOException("Invalid login type."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; } reconnecting = loginType == LoginConstants.TYPE_RECONNECTION; @@ -125,9 +125,8 @@ public final class LoginDecoder extends StatefulFrameDecoder * @param ctx The channel handler context. * @param buffer The buffer. * @param out The {@link List} of objects to pass forward through the pipeline. - * @throws Exception If an error occurs. */ - private void decodePayload(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { + private void decodePayload(ChannelHandlerContext ctx, ByteBuf buffer, List out) { if (buffer.readableBytes() >= loginLength) { ByteBuf payload = buffer.readBytes(loginLength); int clientVersion = 255 - payload.readUnsignedByte(); @@ -136,7 +135,8 @@ public final class LoginDecoder extends StatefulFrameDecoder int lowMemoryFlag = payload.readUnsignedByte(); if (lowMemoryFlag != 0 && lowMemoryFlag != 1) { - throw new Exception("Invalid value for low memory flag."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; } boolean lowMemory = lowMemoryFlag == 1; @@ -148,7 +148,8 @@ public final class LoginDecoder extends StatefulFrameDecoder int securePayloadLength = payload.readUnsignedByte(); if (securePayloadLength != loginLength - 41) { - throw new Exception("Secure payload length mismatch."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; } ByteBuf securePayload = payload.readBytes(securePayloadLength); @@ -160,13 +161,15 @@ public final class LoginDecoder extends StatefulFrameDecoder int secureId = securePayload.readUnsignedByte(); if (secureId != 10) { - throw new Exception("Invalid secure payload id."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; } long clientSeed = securePayload.readLong(); long reportedServerSeed = securePayload.readLong(); if (reportedServerSeed != serverSeed) { - throw new Exception("Server seed mismatch."); + writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); + return; } int uid = securePayload.readInt(); @@ -174,10 +177,9 @@ public final class LoginDecoder extends StatefulFrameDecoder String username = BufferUtil.readString(securePayload); String password = BufferUtil.readString(securePayload); - if (password.length() < 6 || password.length() > 20) { - throw new Exception("Invalid password."); - } else if (username.isEmpty() || username.length() > 12) { - throw new Exception("Invalid username."); + if (password.length() < 6 || password.length() > 20 || username.isEmpty() || username.length() > 12) { + writeResponseCode(ctx, LoginConstants.STATUS_INVALID_CREDENTIALS); + return; } int[] seed = new int[4]; @@ -196,14 +198,23 @@ public final class LoginDecoder extends StatefulFrameDecoder PlayerCredentials credentials = new PlayerCredentials(username, password, usernameHash, uid); IsaacRandomPair randomPair = new IsaacRandomPair(encodingRandom, decodingRandom); - LoginRequest request = new LoginRequest(credentials, randomPair, reconnecting, lowMemory, releaseNumber, archiveCrcs, - clientVersion); + LoginRequest request = new LoginRequest(credentials, randomPair, reconnecting, lowMemory, releaseNumber, archiveCrcs, clientVersion); out.add(request); - if (buffer.isReadable()) { - out.add(buffer.readBytes(buffer.readableBytes())); - } } } + /** + * Writes a response code to the client and closes the current channel. + * + * @param ctx The context of the channel handler. + * @param responseCode The response code to write. + */ + private void writeResponseCode(ChannelHandlerContext ctx, int responseCode) { + ByteBuf buffer = ctx.alloc().buffer(1); + buffer.writeByte(responseCode); + + ctx.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE); + } + } \ No newline at end of file diff --git a/src/org/apollo/util/StatefulFrameDecoder.java b/src/org/apollo/util/StatefulFrameDecoder.java index c34ee522..18234ec2 100644 --- a/src/org/apollo/util/StatefulFrameDecoder.java +++ b/src/org/apollo/util/StatefulFrameDecoder.java @@ -5,8 +5,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import java.util.List; - -import com.google.common.base.Preconditions; +import java.util.Objects; /** * A stateful implementation of a {@link ByteToMessageDecoder} which may be extended and used by other classes. The @@ -17,7 +16,7 @@ import com.google.common.base.Preconditions; * The current state is supplied as a parameter in the {@link StatefulFrameDecoder#decode} and * {@link StatefulFrameDecoder#decodeLast} methods. * - * This class is not thread safe: it is recommended that the state is only set in the decode methods overriden. + * This class is not thread safe: it is recommended that the state is only set in the decode methods overridden. * * @author Graham * @param The state enumeration. @@ -36,17 +35,6 @@ public abstract class StatefulFrameDecoder> extends ByteToMess * @throws NullPointerException If the state is {@code null}. */ public StatefulFrameDecoder(T state) { - this(state, false); - } - - /** - * Creates the stateful frame decoder with the specified initial state and unwrap flag. - * - * @param state The initial state. - * @param unwrap The unwrap flag. - * @throws NullPointerException If the state is {@code null}. - */ - public StatefulFrameDecoder(T state, boolean unwrap) { setState(state); } @@ -66,24 +54,6 @@ public abstract class StatefulFrameDecoder> extends ByteToMess */ protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List out, T state) throws Exception; - @Override - protected final void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List out) { - decodeLast(ctx, in, out, state); - } - - /** - * Decodes remaining data before the channel is closed into a frame. You may override this method, but it is not - * required. If you do not, remaining data will be discarded! - * - * @param ctx The current context of this handler. - * @param in The cumulative buffer, which may contain zero or more bytes. - * @param out The {@link List} of objects to pass forward through the pipeline. - * @param state The current state. The state may be changed by calling {@link #setState}. - */ - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List out, T state) { - - } - /** * Sets a new state. * @@ -91,8 +61,7 @@ public abstract class StatefulFrameDecoder> extends ByteToMess * @throws NullPointerException If the state is {@code null}. */ public final void setState(T state) { - Preconditions.checkNotNull(state, "State cannot be null."); - this.state = state; + this.state = Objects.requireNonNull(state, "State cannot be null."); } } \ No newline at end of file