@Override public void decode(ChannelHandlerContext ctx, ByteBuf buf, MessageBuf<Object> out) throws Exception { if (state == State.READ_OPCODE) { if (!buf.isReadable()) return; opcode = (buf.readUnsignedByte() - cipher.nextInt()) & 0xFF; size = SIZES[opcode]; if (size == -3) { logger.info("invalid opcode: " + opcode); ctx.close(); return; } variable = size == -1; state = variable ? State.READ_SIZE : State.READ_PAYLOAD; } if (state == State.READ_SIZE) { if (!buf.isReadable()) return; size = buf.readUnsignedByte(); state = State.READ_PAYLOAD; } if (state == State.READ_PAYLOAD) { if (buf.readableBytes() < size) return; ByteBuf payload = buf.readBytes(size); state = State.READ_OPCODE; out.add(new GameFrame(opcode, variable ? Type.VARIABLE_BYTE : Type.FIXED, payload)); } }
@SuppressWarnings("unchecked") @Override public void decode(ChannelHandlerContext ctx, GameFrame frame, MessageBuf<Object> out) throws IOException { MessageDecoder<Message> decoder = (MessageDecoder<Message>) codecs.get(frame.getOpcode()); if (decoder == null) { logger.warn("No decoder for packet id " + frame.getOpcode() + "."); return; } out.add(decoder.decode(frame)); }
@Override public void decode(ChannelHandlerContext ctx, ByteBuf buf, MessageBuf<Object> out) { if (buf.readableBytes() < 4) return; out.add(new WorldHandshakeMessage(buf.readInt())); }
@Override public void decode(ChannelHandlerContext ctx, String str, MessageBuf<Object> out) throws Exception { if (!str.startsWith("JAGGRAB ")) { return; } out.add(new JaggrabRequest(str.substring(8))); }
@Override public void decode(ChannelHandlerContext ctx, ByteBuf buf, MessageBuf<Object> out) throws Exception { if (buf.readableBytes() < 4) return; if (state == State.READ_VERSION) { state = State.READ_REQUEST; out.add(new UpdateVersionMessage(buf.readInt())); } else { int opcode = buf.readUnsignedByte(); if (opcode == 0 || opcode == 1) { int type = buf.readUnsignedByte(); int file = buf.readUnsignedShort(); out.add(new FileRequest(opcode == 1, type, file)); } else if (opcode == 4) { int key = buf.readUnsignedByte(); buf.readerIndex(buf.readerIndex() + 2); out.add(new UpdateEncryptionMessage(key)); } else { /* * other unused opcodes: * * 2 - logged in * 3 - logged out * 6 - connection initiated * 7 - connection done */ buf.readerIndex(buf.readerIndex() + 3); return; /* TODO print a warning or add support for reading these opcodes? */ } } }
@Override public void decode(ChannelHandlerContext ctx, ByteBuf buf, MessageBuf<Object> out) throws IOException { if (state == State.READ_SIZE) { if (!buf.isReadable()) return; state = State.READ_PAYLOAD; size = buf.readUnsignedByte(); } if (state == State.READ_PAYLOAD) { if (buf.readableBytes() < size) return; int encryptedSize = buf.readUnsignedByte(); if (encryptedSize != size - 1) throw new IOException("Encrypted size mismatch."); ByteBuf secureBuffer = ByteBufUtils.rsa(buf.readBytes(encryptedSize), RsaKeySet.MODULUS, RsaKeySet.PRIVATE_KEY); int encryptedType = secureBuffer.readUnsignedByte(); if (encryptedType != 10) throw new IOException("Invalid encrypted block type."); secureBuffer.readUnsignedShort(); int version = secureBuffer.readUnsignedShort(); String username = Base37Utils.decodeBase37(secureBuffer.readLong()); secureBuffer.readInt(); String password = ByteBufUtils.readString(secureBuffer); secureBuffer.readInt(); out.add(new AutoLoginRequest(version, username, password)); } }
@Override public void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf<Object> out) { if (state == State.READ_OPCODE) { if (!buffer.isReadable()) return; state = State.READ_LENGTH; opcode = buffer.readUnsignedByte(); } if (state == State.READ_LENGTH) { if (buffer.readableBytes() < 2) return; state = State.READ_PAYLOAD; len = buffer.readUnsignedShort(); } if (state == State.READ_PAYLOAD) { if (buffer.readableBytes() < len) return; state = State.READ_OPCODE; ByteBuf payload = buffer.readBytes(len); out.add(new LoginFrame(opcode, payload)); } }
@SuppressWarnings("unchecked") @Override public void encode(ChannelHandlerContext ctx, Message message, MessageBuf<Object> out) throws IOException { MessageEncoder<Message> encoder = (MessageEncoder<Message>) codecs.get(message.getClass()); out.add(encoder.encode(ctx.alloc(), message)); }
@Override public void decode(ChannelHandlerContext ctx, ByteBuf buf, MessageBuf<Object> out) throws IOException { if (state == State.READ_HEADER) { if (buf.readableBytes() < 4) return; state = State.READ_PAYLOAD; hash = buf.readUnsignedByte(); type = buf.readUnsignedByte(); size = buf.readUnsignedShort(); if (type != 16 && type != 18) throw new IOException("Invalid login type."); } if (state == State.READ_PAYLOAD) { if (buf.readableBytes() < size) return; int version = buf.readInt(); buf.readUnsignedByte(); buf.readUnsignedByte(); buf.readUnsignedByte(); int displayMode = buf.readUnsignedByte(); // 0 = sd, 1 = hd small, 2 = hd resizable int width = buf.readUnsignedShort(); int height = buf.readUnsignedShort(); int antialiasing = buf.readUnsignedByte(); byte[] uid = new byte[24]; for (int i = 0; i < uid.length; i++) uid[i] = buf.readByte(); String settings = ByteBufUtils.readString(buf); int affiliate = buf.readInt(); int flags = buf.readInt(); buf.readShort(); int[] crc = new int[28]; for (int i = 0; i < crc.length; i++) crc[i] = buf.readInt(); int encryptedSize = buf.readUnsignedByte(); ByteBuf secureBuffer = ByteBufUtils.rsa(buf.readBytes(encryptedSize), RsaKeySet.MODULUS, RsaKeySet.PRIVATE_KEY); int encryptedType = secureBuffer.readUnsignedByte(); if (encryptedType != 10) throw new IOException("Invalid encrypted block type."); long clientSessionKey = secureBuffer.readLong(); long serverSessionKey = secureBuffer.readLong(); long encodedUsername = secureBuffer.readLong(); String username = Base37Utils.decodeBase37(encodedUsername); String password = ByteBufUtils.readString(secureBuffer); if (((encodedUsername >> 16) & 31) != hash) throw new IOException("Username hash mismatch."); boolean reconnecting = type == 16; out.add(new LoginRequest(reconnecting, username, password, clientSessionKey, serverSessionKey, version, crc, displayMode)); ctx.pipeline().remove(this); } }
@Override public <T> MessageBuf<T> outboundMessageBuffer() { throw new NotImplementedYet(); }