From cfabff72884e9dbb5f7a8a5feeeb72ec01f8f1e2 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Wed, 19 Jun 2024 10:11:32 +0200 Subject: [PATCH] Implement Velocity PRs #998 #1246 and #1309 (io_uring, tcp_fastopen and PluginMessage race condition fix) --- gradle/libs.versions.toml | 1 + proxy/build.gradle.kts | 3 ++ .../backend/TransitionSessionHandler.java | 8 ++-- .../proxy/network/ConnectionManager.java | 4 +- .../proxy/network/TransportType.java | 40 +++++++++++++++++-- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a3d0523dc..c2d6ab114 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,6 +52,7 @@ netty-codec-haproxy = { module = "io.netty:netty-codec-haproxy", version.ref = " netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" } netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" } netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll", version.ref = "netty" } +netty-transport-native-iouring = { module = "io.netty.incubator:netty-incubator-transport-native-io_uring", version = "0.0.25.Final" } netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" } nightconfig = "com.electronwill.night-config:toml:3.6.7" slf4j = "org.slf4j:slf4j-api:2.0.12" diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 5e1387b06..81c6d9684 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -108,6 +108,9 @@ dependencies { implementation(libs.netty.transport.native.epoll) implementation(variantOf(libs.netty.transport.native.epoll) { classifier("linux-x86_64") }) implementation(variantOf(libs.netty.transport.native.epoll) { classifier("linux-aarch_64") }) + implementation(libs.netty.transport.native.iouring) + implementation(variantOf(libs.netty.transport.native.iouring) { classifier("linux-x86_64") }) + implementation(variantOf(libs.netty.transport.native.iouring) { classifier("linux-aarch_64") }) implementation(libs.netty.transport.native.kqueue) implementation(variantOf(libs.netty.transport.native.kqueue) { classifier("osx-x86_64") }) implementation(variantOf(libs.netty.transport.native.kqueue) { classifier("osx-aarch_64") }) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 6655e3fbf..a74f7c56a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -137,12 +137,14 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { smc.setActiveSessionHandler(StateRegistry.PLAY, new BackendPlaySessionHandler(server, serverConn)); - // Clean up disabling auto-read while the connected event was being processed. - smc.setAutoReading(true); - // Now set the connected server. serverConn.getPlayer().setConnectedServer(serverConn); + // Clean up disabling auto-read while the connected event was being processed. + // Do this after setting the connection, so no incoming packets are processed before + // the API knows which server the player is connected to. + smc.setAutoReading(true); + // Send client settings. In 1.20.2+ this is done in the config state. if (smc.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2) && player.getClientSettingsPacket() != null) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index be1db5522..32e16578f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -100,7 +100,7 @@ public final class ConnectionManager { .childOption(ChannelOption.IP_TOS, 0x18) .localAddress(address); - if (server.getConfiguration().useTcpFastOpen()) { + if (transportType.supportsTcpFastOpenServer() && server.getConfiguration().useTcpFastOpen()) { bootstrap.option(ChannelOption.TCP_FASTOPEN, 3); } @@ -163,7 +163,7 @@ public final class ConnectionManager { this.server.getConfiguration().getConnectTimeout()) .group(group == null ? this.workerGroup : group) .resolver(this.resolver.asGroup()); - if (server.getConfiguration().useTcpFastOpen()) { + if (transportType.supportsTcpFastOpenClient() && server.getConfiguration().useTcpFastOpen()) { bootstrap.option(ChannelOption.TCP_FASTOPEN_CONNECT, true); } return bootstrap; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java b/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java index 6cbdfd8c5..833f0fe48 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java @@ -37,6 +37,8 @@ import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.incubator.channel.uring.*; + import java.util.concurrent.ThreadFactory; import java.util.function.BiFunction; @@ -47,32 +49,50 @@ public enum TransportType { NIO("NIO", NioServerSocketChannel::new, NioSocketChannel::new, NioDatagramChannel::new, - (name, type) -> new NioEventLoopGroup(0, createThreadFactory(name, type))), + (name, type) -> new NioEventLoopGroup(0, createThreadFactory(name, type)), + false, + false), EPOLL("epoll", EpollServerSocketChannel::new, EpollSocketChannel::new, EpollDatagramChannel::new, - (name, type) -> new EpollEventLoopGroup(0, createThreadFactory(name, type))), + (name, type) -> new EpollEventLoopGroup(0, createThreadFactory(name, type)), + Epoll.isTcpFastOpenServerSideAvailable(), + Epoll.isTcpFastOpenClientSideAvailable()), + IO_URING("io_uring", IOUringServerSocketChannel::new, + IOUringSocketChannel::new, + IOUringDatagramChannel::new, + (name, type) -> new IOUringEventLoopGroup(0, createThreadFactory(name, type)), + IOUring.isTcpFastOpenServerSideAvailable(), + IOUring.isTcpFastOpenClientSideAvailable()), KQUEUE("kqueue", KQueueServerSocketChannel::new, KQueueSocketChannel::new, KQueueDatagramChannel::new, - (name, type) -> new KQueueEventLoopGroup(0, createThreadFactory(name, type))); + (name, type) -> new KQueueEventLoopGroup(0, createThreadFactory(name, type)), + KQueue.isTcpFastOpenServerSideAvailable(), + KQueue.isTcpFastOpenClientSideAvailable()); final String name; final ChannelFactory serverSocketChannelFactory; final ChannelFactory socketChannelFactory; final ChannelFactory datagramChannelFactory; final BiFunction eventLoopGroupFactory; + final boolean supportsTcpFastOpenServer; + final boolean supportsTcpFastOpenClient; TransportType(final String name, final ChannelFactory serverSocketChannelFactory, final ChannelFactory socketChannelFactory, final ChannelFactory datagramChannelFactory, - final BiFunction eventLoopGroupFactory) { + final BiFunction eventLoopGroupFactory, + final boolean supportsTcpFastOpenServer, + final boolean supportsTcpFastOpenClient) { this.name = name; this.serverSocketChannelFactory = serverSocketChannelFactory; this.socketChannelFactory = socketChannelFactory; this.datagramChannelFactory = datagramChannelFactory; this.eventLoopGroupFactory = eventLoopGroupFactory; + this.supportsTcpFastOpenServer = supportsTcpFastOpenServer; + this.supportsTcpFastOpenClient = supportsTcpFastOpenClient; } @Override @@ -84,6 +104,14 @@ public enum TransportType { return this.eventLoopGroupFactory.apply(this.name, type); } + public boolean supportsTcpFastOpenServer() { + return supportsTcpFastOpenServer; + } + + public boolean supportsTcpFastOpenClient() { + return supportsTcpFastOpenClient; + } + private static ThreadFactory createThreadFactory(final String name, final Type type) { return new VelocityNettyThreadFactory("Netty " + name + ' ' + type.toString() + " #%d"); } @@ -98,6 +126,10 @@ public enum TransportType { return NIO; } + if(IOUring.isAvailable()) { + return IO_URING; + } + if (Epoll.isAvailable()) { return EPOLL; }