Skip to content

Commit 173f07c

Browse files
authored
Merge pull request #31 from PaperMC/dev/3.0.0
[pull] main from PaperMC:dev/3.0.0
2 parents 89117bf + dc65953 commit 173f07c

File tree

10 files changed

+111
-9
lines changed

10 files changed

+111
-9
lines changed

proxy/src/main/java/com/velocitypowered/proxy/Velocity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public class Velocity {
4747
System.setProperty("io.netty.native.workdir", System.getProperty("velocity.natives-tmpdir"));
4848
}
4949

50+
// Restore allocator used before Netty 4.2 due to oom issues with the adaptive allocator
51+
if (System.getProperty("io.netty.allocator.type") == null) {
52+
System.setProperty("io.netty.allocator.type", "pooled");
53+
}
54+
5055
// Disable the resource leak detector by default as it reduces performance. Allow the user to
5156
// override this if desired.
5257
if (!VelocityProperties.hasProperty("io.netty.leakDetection.level")) {

proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.velocitypowered.proxy.protocol.netty.MinecraftCompressorAndLengthEncoder;
4747
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
4848
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
49+
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
4950
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
5051
import com.velocitypowered.proxy.protocol.netty.PlayPacketQueueInboundHandler;
5152
import com.velocitypowered.proxy.protocol.netty.PlayPacketQueueOutboundHandler;
@@ -368,6 +369,11 @@ public void setState(StateRegistry state) {
368369
ensureInEventLoop();
369370

370371
this.state = state;
372+
final MinecraftVarintFrameDecoder frameDecoder = this.channel.pipeline()
373+
.get(MinecraftVarintFrameDecoder.class);
374+
if (frameDecoder != null) {
375+
frameDecoder.setState(state);
376+
}
371377
// If the connection is LEGACY (<1.6), the decoder and encoder are not set.
372378
final MinecraftEncoder minecraftEncoder = this.channel.pipeline()
373379
.get(MinecraftEncoder.class);

proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.velocitypowered.proxy.protocol.MinecraftPacket;
4848
import com.velocitypowered.proxy.protocol.StateRegistry;
4949
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
50+
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
5051
import com.velocitypowered.proxy.protocol.packet.AvailableCommandsPacket;
5152
import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
5253
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
@@ -149,6 +150,7 @@ public boolean handle(StartUpdatePacket packet) {
149150
MinecraftConnection smc = serverConn.ensureConnected();
150151
smc.setAutoReading(false);
151152
// Even when not auto reading messages are still decoded. Decode them with the correct state
153+
smc.getChannel().pipeline().get(MinecraftVarintFrameDecoder.class).setState(StateRegistry.CONFIG);
152154
smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.CONFIG);
153155
serverConn.getPlayer().switchToConfigState();
154156
return true;

proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.velocitypowered.proxy.protocol.MinecraftPacket;
4141
import com.velocitypowered.proxy.protocol.StateRegistry;
4242
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
43+
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
4344
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
4445
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
4546
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
@@ -232,6 +233,7 @@ public boolean handle(FinishedUpdatePacket packet) {
232233
final ConnectedPlayer player = serverConn.getPlayer();
233234
final ClientConfigSessionHandler configHandler = (ClientConfigSessionHandler) player.getConnection().getActiveSessionHandler();
234235

236+
smc.getChannel().pipeline().get(MinecraftVarintFrameDecoder.class).setState(StateRegistry.PLAY);
235237
smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.PLAY);
236238
//noinspection DataFlowIssue
237239
configHandler.handleBackendFinishUpdate(serverConn).thenRunAsync(() -> {

proxy/src/main/java/com/velocitypowered/proxy/network/BackendChannelInitializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public BackendChannelInitializer(VelocityServer server) {
5151
@Override
5252
protected void initChannel(Channel ch) {
5353
ch.pipeline()
54-
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
54+
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.CLIENTBOUND))
5555
.addLast(READ_TIMEOUT,
5656
new ReadTimeoutHandler(server.getConfiguration().getReadTimeout(),
5757
TimeUnit.MILLISECONDS))

proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import com.velocitypowered.proxy.protocol.netty.GameSpyQueryHandler;
3030
import io.netty.bootstrap.Bootstrap;
3131
import io.netty.bootstrap.ServerBootstrap;
32-
import io.netty.buffer.PooledByteBufAllocator;
3332
import io.netty.channel.Channel;
3433
import io.netty.channel.ChannelFuture;
3534
import io.netty.channel.ChannelFutureListener;
@@ -117,11 +116,6 @@ public void bind(final InetSocketAddress address) {
117116
bootstrap.group(this.bossGroup, this.workerGroup);
118117
}
119118

120-
// Restore allocator used before Netty 4.2 due to oom issues with the adaptive allocator
121-
if (System.getProperty("io.netty.allocator.type") == null) {
122-
bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
123-
}
124-
125119
final int binds = server.getConfiguration().isEnableReusePort()
126120
? ((MultithreadEventExecutorGroup) this.workerGroup).executorCount() : 1;
127121

proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public ServerChannelInitializer(final VelocityServer server) {
5858
protected void initChannel(final Channel ch) {
5959
ch.pipeline()
6060
.addLast(LEGACY_PING_DECODER, new LegacyPingDecoder())
61-
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
61+
.addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.SERVERBOUND))
6262
.addLast(READ_TIMEOUT,
6363
new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(),
6464
TimeUnit.MILLISECONDS))

proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,48 @@
1919

2020
import static io.netty.util.ByteProcessor.FIND_NON_NUL;
2121

22+
import com.velocitypowered.api.network.ProtocolVersion;
23+
import com.velocitypowered.proxy.protocol.MinecraftPacket;
24+
import com.velocitypowered.proxy.protocol.ProtocolUtils;
25+
import com.velocitypowered.proxy.protocol.StateRegistry;
2226
import com.velocitypowered.proxy.util.except.QuietDecoderException;
27+
import com.velocitypowered.proxy.util.except.QuietRuntimeException;
2328
import io.netty.buffer.ByteBuf;
2429
import io.netty.channel.ChannelHandlerContext;
2530
import io.netty.handler.codec.ByteToMessageDecoder;
31+
import io.netty.handler.codec.CorruptedFrameException;
2632
import java.util.List;
2733

2834
/**
2935
* Frames Minecraft server packets which are prefixed by a 21-bit VarInt encoding.
3036
*/
3137
public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
3238

39+
private static final QuietRuntimeException FRAME_DECODER_FAILED =
40+
new QuietRuntimeException("A packet frame decoder failed. For more information, launch "
41+
+ "Velocity with -Dvelocity.packet-decode-logging=true to see more.");
3342
private static final QuietDecoderException BAD_PACKET_LENGTH =
3443
new QuietDecoderException("Bad packet length");
3544
private static final QuietDecoderException VARINT_TOO_BIG =
3645
new QuietDecoderException("VarInt too big");
46+
private static final QuietDecoderException UNKNOWN_PACKET =
47+
new QuietDecoderException("Unknown packet");
48+
49+
private final ProtocolUtils.Direction direction;
50+
private final StateRegistry.PacketRegistry.ProtocolRegistry registry;
51+
private StateRegistry state;
52+
53+
/**
54+
* Creates a new {@code MinecraftVarintFrameDecoder} decoding packets from the specified {@code Direction}.
55+
*
56+
* @param direction the direction from which we decode from
57+
*/
58+
public MinecraftVarintFrameDecoder(ProtocolUtils.Direction direction) {
59+
this.direction = direction;
60+
this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry(
61+
direction, ProtocolVersion.MINIMUM_VERSION);
62+
this.state = StateRegistry.HANDSHAKE;
63+
}
3764

3865
@Override
3966
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
@@ -62,6 +89,38 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
6289
throw BAD_PACKET_LENGTH;
6390
}
6491

92+
if (length > 0) {
93+
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
94+
StateRegistry.PacketRegistry.ProtocolRegistry registry =
95+
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
96+
97+
final int index = in.readerIndex();
98+
final int packetId = ProtocolUtils.readVarInt(in);
99+
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
100+
101+
MinecraftPacket packet = registry.createPacket(packetId);
102+
103+
// We handle every packet in this phase, if you said something we don't know, something is really wrong
104+
if (packet == null) {
105+
throw UNKNOWN_PACKET;
106+
}
107+
108+
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
109+
// the packet if needed, so, we'll take advantage of the existing methods
110+
int expectedMinLen = packet.expectedMinLength(in, direction, registry.version);
111+
int expectedMaxLen = packet.expectedMaxLength(in, direction, registry.version);
112+
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
113+
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
114+
}
115+
if (payloadLength < expectedMinLen) {
116+
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
117+
}
118+
119+
120+
in.readerIndex(index);
121+
}
122+
}
123+
65124
// note that zero-length packets are ignored
66125
if (length > 0) {
67126
if (in.readableBytes() < length) {
@@ -141,4 +200,26 @@ private static int readRawVarintSmallBuf(ByteBuf buffer) {
141200
}
142201
return result | (tmp & 0x7F) << 14;
143202
}
203+
204+
private Exception handleOverflow(MinecraftPacket packet, int expected, int actual) {
205+
if (MinecraftDecoder.DEBUG) {
206+
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
207+
+ "big (expected " + expected + " bytes, got " + actual + " bytes)");
208+
} else {
209+
return FRAME_DECODER_FAILED;
210+
}
211+
}
212+
213+
private Exception handleUnderflow(MinecraftPacket packet, int expected, int actual) {
214+
if (MinecraftDecoder.DEBUG) {
215+
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
216+
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
217+
} else {
218+
return FRAME_DECODER_FAILED;
219+
}
220+
}
221+
222+
public void setState(StateRegistry stateRegistry) {
223+
this.state = stateRegistry;
224+
}
144225
}

proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,16 @@ public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersi
106106
public boolean handle(MinecraftSessionHandler handler) {
107107
return handler.handle(this);
108108
}
109+
110+
@Override
111+
public int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
112+
ProtocolVersion version) {
113+
return 7;
114+
}
115+
116+
@Override
117+
public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
118+
ProtocolVersion version) {
119+
return 270;
120+
}
109121
}

proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public CompletableFuture<ServerPing> ping(@Nullable EventLoop loop, PingOptions
114114
server.createBootstrap(loop).handler(new ChannelInitializer<>() {
115115
@Override
116116
protected void initChannel(Channel ch) {
117-
ch.pipeline().addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder())
117+
ch.pipeline().addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.CLIENTBOUND))
118118
.addLast(READ_TIMEOUT, new ReadTimeoutHandler(
119119
pingOptions.getTimeout() == 0
120120
? server.getConfiguration().getReadTimeout()

0 commit comments

Comments
 (0)