mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-06 16:51:37 +00:00
Merge branch 'net'.
This commit is contained in:
@@ -4,7 +4,6 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.burtleburtle.bob.rand.IsaacRandom;
|
import net.burtleburtle.bob.rand.IsaacRandom;
|
||||||
@@ -61,7 +60,7 @@ public final class GamePacketDecoder extends StatefulFrameDecoder<GameDecoderSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out, GameDecoderState state) throws IOException {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out, GameDecoderState state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case GAME_OPCODE:
|
case GAME_OPCODE:
|
||||||
decodeOpcode(in, out);
|
decodeOpcode(in, out);
|
||||||
@@ -96,9 +95,8 @@ public final class GamePacketDecoder extends StatefulFrameDecoder<GameDecoderSta
|
|||||||
*
|
*
|
||||||
* @param buffer The buffer.
|
* @param buffer The buffer.
|
||||||
* @param out The {@link List} of objects to be passed along the pipeline.
|
* @param out The {@link List} of objects to be passed along the pipeline.
|
||||||
* @throws IOException If a received opcode or packet type is illegal.
|
|
||||||
*/
|
*/
|
||||||
private void decodeOpcode(ByteBuf buffer, List<Object> out) throws IOException {
|
private void decodeOpcode(ByteBuf buffer, List<Object> out) {
|
||||||
if (buffer.isReadable()) {
|
if (buffer.isReadable()) {
|
||||||
int encryptedOpcode = buffer.readUnsignedByte();
|
int encryptedOpcode = buffer.readUnsignedByte();
|
||||||
opcode = encryptedOpcode - random.nextInt() & 0xFF;
|
opcode = encryptedOpcode - random.nextInt() & 0xFF;
|
||||||
@@ -121,7 +119,7 @@ public final class GamePacketDecoder extends StatefulFrameDecoder<GameDecoderSta
|
|||||||
setState(GameDecoderState.GAME_LENGTH);
|
setState(GameDecoderState.GAME_LENGTH);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IOException("Illegal packet type: " + type + ".");
|
throw new IllegalStateException("Illegal packet type: " + type + ".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package org.apollo.net.codec.login;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -28,7 +28,7 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
/**
|
/**
|
||||||
* The secure random number generator.
|
* The secure random number generator.
|
||||||
*/
|
*/
|
||||||
private static final SecureRandom random = new SecureRandom();
|
private static final SecureRandom RANDOM = new SecureRandom();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The login packet length.
|
* The login packet length.
|
||||||
@@ -54,11 +54,11 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
* Creates the login decoder with the default initial state.
|
* Creates the login decoder with the default initial state.
|
||||||
*/
|
*/
|
||||||
public LoginDecoder() {
|
public LoginDecoder() {
|
||||||
super(LoginDecoderState.LOGIN_HANDSHAKE, true);
|
super(LoginDecoderState.LOGIN_HANDSHAKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out, LoginDecoderState state) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out, LoginDecoderState state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case LOGIN_HANDSHAKE:
|
case LOGIN_HANDSHAKE:
|
||||||
decodeHandshake(ctx, in, out);
|
decodeHandshake(ctx, in, out);
|
||||||
@@ -70,7 +70,7 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
decodePayload(ctx, in, out);
|
decodePayload(ctx, in, out);
|
||||||
break;
|
break;
|
||||||
default:
|
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<LoginDecoderState>
|
|||||||
private void decodeHandshake(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) {
|
private void decodeHandshake(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) {
|
||||||
if (buffer.isReadable()) {
|
if (buffer.isReadable()) {
|
||||||
usernameHash = buffer.readUnsignedByte();
|
usernameHash = buffer.readUnsignedByte();
|
||||||
serverSeed = random.nextLong();
|
serverSeed = RANDOM.nextLong();
|
||||||
|
|
||||||
ByteBuf response = ctx.alloc().buffer(17);
|
ByteBuf response = ctx.alloc().buffer(17);
|
||||||
response.writeByte(LoginConstants.STATUS_EXCHANGE_DATA);
|
response.writeByte(LoginConstants.STATUS_EXCHANGE_DATA);
|
||||||
@@ -102,14 +102,14 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
* @param ctx The channel handler context.
|
* @param ctx The channel handler context.
|
||||||
* @param buffer The buffer.
|
* @param buffer The buffer.
|
||||||
* @param out The {@link List} of objects to pass forward through the pipeline.
|
* @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<Object> out) throws IOException {
|
private void decodeHeader(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) {
|
||||||
if (buffer.readableBytes() >= 2) {
|
if (buffer.readableBytes() >= 2) {
|
||||||
int loginType = buffer.readUnsignedByte();
|
int loginType = buffer.readUnsignedByte();
|
||||||
|
|
||||||
if (loginType != LoginConstants.TYPE_STANDARD && loginType != LoginConstants.TYPE_RECONNECTION) {
|
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;
|
reconnecting = loginType == LoginConstants.TYPE_RECONNECTION;
|
||||||
@@ -125,9 +125,8 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
* @param ctx The channel handler context.
|
* @param ctx The channel handler context.
|
||||||
* @param buffer The buffer.
|
* @param buffer The buffer.
|
||||||
* @param out The {@link List} of objects to pass forward through the pipeline.
|
* @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<Object> out) throws Exception {
|
private void decodePayload(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) {
|
||||||
if (buffer.readableBytes() >= loginLength) {
|
if (buffer.readableBytes() >= loginLength) {
|
||||||
ByteBuf payload = buffer.readBytes(loginLength);
|
ByteBuf payload = buffer.readBytes(loginLength);
|
||||||
int clientVersion = 255 - payload.readUnsignedByte();
|
int clientVersion = 255 - payload.readUnsignedByte();
|
||||||
@@ -136,7 +135,8 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
|
|
||||||
int lowMemoryFlag = payload.readUnsignedByte();
|
int lowMemoryFlag = payload.readUnsignedByte();
|
||||||
if (lowMemoryFlag != 0 && lowMemoryFlag != 1) {
|
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;
|
boolean lowMemory = lowMemoryFlag == 1;
|
||||||
@@ -148,7 +148,8 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
|
|
||||||
int securePayloadLength = payload.readUnsignedByte();
|
int securePayloadLength = payload.readUnsignedByte();
|
||||||
if (securePayloadLength != loginLength - 41) {
|
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);
|
ByteBuf securePayload = payload.readBytes(securePayloadLength);
|
||||||
@@ -160,13 +161,15 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
|
|
||||||
int secureId = securePayload.readUnsignedByte();
|
int secureId = securePayload.readUnsignedByte();
|
||||||
if (secureId != 10) {
|
if (secureId != 10) {
|
||||||
throw new Exception("Invalid secure payload id.");
|
writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long clientSeed = securePayload.readLong();
|
long clientSeed = securePayload.readLong();
|
||||||
long reportedServerSeed = securePayload.readLong();
|
long reportedServerSeed = securePayload.readLong();
|
||||||
if (reportedServerSeed != serverSeed) {
|
if (reportedServerSeed != serverSeed) {
|
||||||
throw new Exception("Server seed mismatch.");
|
writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uid = securePayload.readInt();
|
int uid = securePayload.readInt();
|
||||||
@@ -174,10 +177,9 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
String username = BufferUtil.readString(securePayload);
|
String username = BufferUtil.readString(securePayload);
|
||||||
String password = BufferUtil.readString(securePayload);
|
String password = BufferUtil.readString(securePayload);
|
||||||
|
|
||||||
if (password.length() < 6 || password.length() > 20) {
|
if (password.length() < 6 || password.length() > 20 || username.isEmpty() || username.length() > 12) {
|
||||||
throw new Exception("Invalid password.");
|
writeResponseCode(ctx, LoginConstants.STATUS_INVALID_CREDENTIALS);
|
||||||
} else if (username.isEmpty() || username.length() > 12) {
|
return;
|
||||||
throw new Exception("Invalid username.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] seed = new int[4];
|
int[] seed = new int[4];
|
||||||
@@ -196,14 +198,23 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
|
|||||||
PlayerCredentials credentials = new PlayerCredentials(username, password, usernameHash, uid);
|
PlayerCredentials credentials = new PlayerCredentials(username, password, usernameHash, uid);
|
||||||
IsaacRandomPair randomPair = new IsaacRandomPair(encodingRandom, decodingRandom);
|
IsaacRandomPair randomPair = new IsaacRandomPair(encodingRandom, decodingRandom);
|
||||||
|
|
||||||
LoginRequest request = new LoginRequest(credentials, randomPair, reconnecting, lowMemory, releaseNumber, archiveCrcs,
|
LoginRequest request = new LoginRequest(credentials, randomPair, reconnecting, lowMemory, releaseNumber, archiveCrcs, clientVersion);
|
||||||
clientVersion);
|
|
||||||
|
|
||||||
out.add(request);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,8 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stateful implementation of a {@link ByteToMessageDecoder} which may be extended and used by other classes. The
|
* 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
|
* The current state is supplied as a parameter in the {@link StatefulFrameDecoder#decode} and
|
||||||
* {@link StatefulFrameDecoder#decodeLast} methods.
|
* {@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
|
* @author Graham
|
||||||
* @param <T> The state enumeration.
|
* @param <T> The state enumeration.
|
||||||
@@ -36,17 +35,6 @@ public abstract class StatefulFrameDecoder<T extends Enum<T>> extends ByteToMess
|
|||||||
* @throws NullPointerException If the state is {@code null}.
|
* @throws NullPointerException If the state is {@code null}.
|
||||||
*/
|
*/
|
||||||
public StatefulFrameDecoder(T state) {
|
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);
|
setState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,24 +54,6 @@ public abstract class StatefulFrameDecoder<T extends Enum<T>> extends ByteToMess
|
|||||||
*/
|
*/
|
||||||
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out, T state) throws Exception;
|
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out, T state) throws Exception;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> 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<Object> out, T state) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new state.
|
* Sets a new state.
|
||||||
*
|
*
|
||||||
@@ -91,8 +61,7 @@ public abstract class StatefulFrameDecoder<T extends Enum<T>> extends ByteToMess
|
|||||||
* @throws NullPointerException If the state is {@code null}.
|
* @throws NullPointerException If the state is {@code null}.
|
||||||
*/
|
*/
|
||||||
public final void setState(T state) {
|
public final void setState(T state) {
|
||||||
Preconditions.checkNotNull(state, "State cannot be null.");
|
this.state = Objects.requireNonNull(state, "State cannot be null.");
|
||||||
this.state = state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user