Yatopia/patches/server/0063-New-Network-System.patch

320 lines
14 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hugo Planque <hookwood01@gmail.com>
Date: Mon, 18 Jan 2021 11:27:08 +0100
Subject: [PATCH] New Network System
Co-authored-by: Ivan Pekov <ivan@mrivanplays.com>
diff --git a/pom.xml b/pom.xml
index 8af1a91102c5cc4c230f622e6629e46e95f17d44..9b7ed0de1054285dadff6aefc95c7207079504a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,9 +53,17 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
- <version>4.1.50.Final</version>
+ <version>4.1.58.Final</version> <!-- Yatopia -->
</dependency>
<!-- Tuinity end - fix compile issue (cannot see new api) by moving netty include BEFORE server jar -->
+ <!-- Yatopia start - Add IOUring beta support -->
+ <dependency>
+ <groupId>io.netty.incubator</groupId>
+ <artifactId>netty-incubator-transport-native-io_uring</artifactId>
+ <version>0.0.3.Final</version>
+ <classifier>linux-x86_64</classifier>
+ </dependency>
+ <!-- Yatopia end -->
<dependency>
<groupId>io.papermc</groupId>
<artifactId>minecraft-server</artifactId>
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 87cf9cd88d1fb5ae70d19e5618ebfb67d281304a..a1c2bea7c93433434b4e4dfd0bb4b9620657c40d 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1740,6 +1740,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
return true;
}
+ public final boolean isUsingNativeTransport() { return l(); } // Yatopia - OBFHELPER
public abstract boolean l();
public boolean getPVP() {
diff --git a/src/main/java/net/minecraft/server/ServerConnection.java b/src/main/java/net/minecraft/server/ServerConnection.java
index 0668d383db1f3a81d1053954d72678c7ac5aecec..d22f0ee3f7f2daa8323d454aca1f94733b249333 100644
--- a/src/main/java/net/minecraft/server/ServerConnection.java
+++ b/src/main/java/net/minecraft/server/ServerConnection.java
@@ -11,6 +11,7 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
+import io.netty.channel.epoll.EpollChannelOption; // Yatopia
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
@@ -26,6 +27,7 @@ import java.util.List;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.yatopiamc.yatopia.server.network.NetworkType; // Yatopia
public class ServerConnection {
@@ -52,15 +54,29 @@ public class ServerConnection {
}
// Paper end
+ // Yatopia start - New network system
+ private final NetworkType networkType;
+ private final EventLoopGroup boss, worker;
+ // Yatopia end
+
public ServerConnection(MinecraftServer minecraftserver) {
this.e = minecraftserver;
this.c = true;
+
+ // Yatopia start - New network system
+ this.networkType = NetworkType.bestType(minecraftserver, LOGGER);
+ this.boss = networkType.createEventLoopGroup(NetworkType.LoopGroupType.BOSS);
+ this.worker = networkType.createEventLoopGroup(NetworkType.LoopGroupType.WORKER);
+ // Yatopia end
}
public void a(@Nullable InetAddress inetaddress, int i) throws IOException {
+ /* // Yatopia start - New network system
List list = this.listeningChannels;
+ */
synchronized (this.listeningChannels) {
+ /*
Class oclass;
LazyInitVar lazyinitvar;
@@ -73,16 +89,25 @@ public class ServerConnection {
lazyinitvar = ServerConnection.a;
ServerConnection.LOGGER.info("Using default channel type");
}
+ */
+
// Tuinity start - indicate Velocity natives in use
ServerConnection.LOGGER.info("Tuinity: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity.");
ServerConnection.LOGGER.info("Tuinity: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity.");
// Tuinity end
- this.listeningChannels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
+ ServerConnection.LOGGER.info("Yatopia: Using " + networkType.getName() + " network type.");
+ ServerBootstrap serverBootstrap = new ServerBootstrap();
+
+ if (org.yatopiamc.yatopia.server.YatopiaConfig.tcpFastOpen && networkType == NetworkType.EPOLL) {
+ serverBootstrap.option(EpollChannelOption.TCP_FASTOPEN, 3); // Will improve the connection with some speed
+ }
+ this.listeningChannels.add((((serverBootstrap).channelFactory(networkType.getServerSocketChannelFactory())).childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) throws Exception {
try {
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
+ channel.config().setOption(ChannelOption.IP_TOS, 0x18); // Change the priority of the packet to immediate
} catch (ChannelException channelexception) {
;
}
@@ -97,7 +122,8 @@ public class ServerConnection {
channel.pipeline().addLast("packet_handler", (ChannelHandler) object);
((NetworkManager) object).setPacketListener(new HandshakeListener(ServerConnection.this.e, (NetworkManager) object));
}
- }).group((EventLoopGroup) lazyinitvar.a()).localAddress(inetaddress, i)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit
+ }).group(boss, worker).localAddress(inetaddress, i)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit
+ // Yatopia end
}
}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
index c2dc5265552ebd429111253c70481003a4be29dd..c67654e8701b9da6499d442048429149daae7150 100644
--- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
@@ -271,4 +271,17 @@ public class YatopiaConfig {
logPlayerLoginLoc = getBoolean("settings.log-player-login-location", logPlayerLoginLoc);
}
+ public static boolean ioUringBeta = false;
+ public static boolean tcpFastOpen = false;
+ public static boolean debugNetwork = false;
+ private static void newNetworkSystem() {
+ ioUringBeta = getBoolean("network.io-uring", ioUringBeta);
+ if (config.get("network.ftcp-fastopen") != null) {
+ config.set("network.tcp-fastopen", getBoolean("network.ftcp-fastopen", tcpFastOpen));
+ config.set("network.ftcp-fastopen", null);
+ }
+ tcpFastOpen = getBoolean("network.tcp-fastopen", tcpFastOpen);
+ debugNetwork = getBoolean("network.debug", debugNetwork);
+ }
+
}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/network/NettyThreadFactory.java b/src/main/java/org/yatopiamc/yatopia/server/network/NettyThreadFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e74e23f3cc44b7547d9f8575b411059e0e65449
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/network/NettyThreadFactory.java
@@ -0,0 +1,27 @@
+package org.yatopiamc.yatopia.server.network;
+
+import io.netty.util.concurrent.FastThreadLocalThread;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Based off of Velocity's VelocityNettyThreadFactory
+ */
+public class NettyThreadFactory implements ThreadFactory {
+
+ private final AtomicInteger threadNumber = new AtomicInteger();
+ private final String networkTypeName, loopGroupTypeName;
+
+ public NettyThreadFactory(String networkTypeName, String loopGroupTypeName) {
+ this.networkTypeName = networkTypeName;
+ this.loopGroupTypeName = loopGroupTypeName;
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ return new FastThreadLocalThread(
+ r,
+ "Netty " + networkTypeName + " " + loopGroupTypeName + " #" + threadNumber.getAndIncrement()
+ );
+ }
+}
diff --git a/src/main/java/org/yatopiamc/yatopia/server/network/NetworkType.java b/src/main/java/org/yatopiamc/yatopia/server/network/NetworkType.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c387f29e4db7e1574a2bbb119465c48b8ed2f90
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/network/NetworkType.java
@@ -0,0 +1,129 @@
+package org.yatopiamc.yatopia.server.network;
+
+import io.netty.channel.ChannelFactory;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.Epoll;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
+import io.netty.channel.kqueue.KQueue;
+import io.netty.channel.kqueue.KQueueEventLoopGroup;
+import io.netty.channel.kqueue.KQueueServerSocketChannel;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.ServerSocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.incubator.channel.uring.IOUring;
+import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
+import io.netty.incubator.channel.uring.IOUringServerSocketChannel;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.function.BiFunction;
+
+import net.minecraft.server.MinecraftServer;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.spigotmc.SpigotConfig;
+import org.yatopiamc.yatopia.server.YatopiaConfig;
+
+/**
+ * Based off of Velocity's TransportType
+ */
+public enum NetworkType {
+ NIO("NIO", NioServerSocketChannel::new, (name, type) -> new NioEventLoopGroup(8, createThreadFactory(name, type))),
+
+ EPOLL("Epoll", EpollServerSocketChannel::new, (name, type) -> new EpollEventLoopGroup(8, createThreadFactory(name, type))),
+
+ IOURING("IOUring", IOUringServerSocketChannel::new, (name, type) -> new IOUringEventLoopGroup(8, createThreadFactory(name, type))),
+
+ KQUEUE("KQueue", KQueueServerSocketChannel::new, (name, type) -> new KQueueEventLoopGroup(8, createThreadFactory(name, type)));
+
+ public final String name;
+ public final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory;
+ public final BiFunction<String, LoopGroupType, EventLoopGroup> eventLoopGroupFactory;
+
+ NetworkType(final String name,
+ final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory,
+ final BiFunction<String, LoopGroupType, EventLoopGroup> eventLoopGroupFactory) {
+ this.name = name;
+ this.serverSocketChannelFactory = serverSocketChannelFactory;
+ this.eventLoopGroupFactory = eventLoopGroupFactory;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ChannelFactory<? extends ServerSocketChannel> getServerSocketChannelFactory() {
+ return serverSocketChannelFactory;
+ }
+
+ @Override
+ public String toString() {
+ return this.name;
+ }
+
+ public EventLoopGroup createEventLoopGroup(final LoopGroupType type) {
+ return this.eventLoopGroupFactory.apply(this.name, type);
+ }
+
+ private static ThreadFactory createThreadFactory(final String name, final LoopGroupType type) {
+ return new NettyThreadFactory(name, type.toString());
+ }
+
+ public static NetworkType bestType(MinecraftServer minecraftServer, Logger logger) {
+ if (!minecraftServer.isUsingNativeTransport()) {
+ return NIO;
+ }
+ // Actually, there is a decompression problem with zlib from bungeecord that makes
+ // IOUring not available on spigot server with bungeecord
+ // https://github.com/netty/netty-incubator-transport-io_uring/issues/40
+ // Looks like iouring send very small compressed packet and trigger PacketDecompressor
+ if (!SpigotConfig.bungee && YatopiaConfig.ioUringBeta && MinecraftServer.getServer().ax() < 0) {
+ if (IOUring.isAvailable()) {
+ return IOURING;
+ } else if (YatopiaConfig.debugNetwork) {
+ logger.log(Level.ERROR, "IOUring is not working: {}", exceptionMessage(IOUring.unavailabilityCause()));
+ }
+ }
+
+ if (Epoll.isAvailable()) {
+ return EPOLL;
+ } else if (YatopiaConfig.debugNetwork) {
+ logger.log(Level.ERROR, "Epoll is not working: {}", exceptionMessage(Epoll.unavailabilityCause()));
+ }
+
+ if (KQueue.isAvailable()) {
+ return KQUEUE;
+ } else if (YatopiaConfig.debugNetwork) {
+ logger.log(Level.ERROR, "KQueue is not working: {}", exceptionMessage(KQueue.unavailabilityCause()));
+ }
+
+ return NIO;
+ }
+
+ private static String exceptionMessage(Throwable throwable) {
+ StackTraceElement[] trace = throwable.getStackTrace();
+ return getClassNameFromString(throwable.getClass().getName()) + " : " + throwable.getMessage() +
+ ((trace.length > 0) ? " @ " + throwable.getStackTrace()[0].getClassName() + ":" + throwable.getStackTrace()[0].getLineNumber() : "");
+ }
+
+ private static String getClassNameFromString(String className) {
+ int i = className.lastIndexOf('.');
+ return i > 0 ? className.substring(i + 1) : className;
+ }
+
+ public enum LoopGroupType {
+ BOSS("Boss"),
+ WORKER("Worker");
+
+ private final String name;
+
+ LoopGroupType(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return this.name;
+ }
+ }
+}