mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Fix: Properly check whether the so_reuseport
socket option is available (#4579)
* Try to properly check if so_reuseport is available * io_uring "support" * comment out io_uring, for now * Make IO_uring opt-in via `-DGeyser.io_uring=true` flag * dont include io_uring * oops - bungee editing on mobile is hard * oops - spigot * oops - velocity * properly exclude all io_uring on all platforms except standalone --------- Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
This commit is contained in:
parent
c3ffd65f48
commit
94f664ad8d
9 changed files with 56 additions and 19 deletions
|
@ -47,6 +47,8 @@ dependencies {
|
|||
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } }
|
||||
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } }
|
||||
implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } }
|
||||
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-x86_64" } }
|
||||
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-aarch_64" } }
|
||||
|
||||
// Adventure text serialization
|
||||
api(libs.bundles.adventure)
|
||||
|
@ -66,11 +68,6 @@ dependencies {
|
|||
api(libs.events)
|
||||
}
|
||||
|
||||
configurations.api {
|
||||
// This is still experimental - additionally, it could only really benefit standalone
|
||||
exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring")
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle.
|
||||
// It used to be generated by the maven Git-Commit-Id-Plugin
|
||||
|
|
|
@ -49,6 +49,7 @@ public final class Bootstraps {
|
|||
String kernelVersion;
|
||||
try {
|
||||
kernelVersion = Native.KERNEL_VERSION;
|
||||
GeyserImpl.getInstance().getLogger().debug("Kernel version: " + kernelVersion);
|
||||
} catch (Throwable e) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Could not determine kernel version! " + e.getMessage());
|
||||
kernelVersion = null;
|
||||
|
@ -67,10 +68,22 @@ public final class Bootstraps {
|
|||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes, unchecked"})
|
||||
public static void setupBootstrap(AbstractBootstrap bootstrap) {
|
||||
public static boolean setupBootstrap(AbstractBootstrap bootstrap) {
|
||||
boolean success = true;
|
||||
if (REUSEPORT_AVAILABLE) {
|
||||
bootstrap.option(UnixChannelOption.SO_REUSEPORT, true);
|
||||
// Guessing whether so_reuseport is available based on kernel version is cool, but unreliable.
|
||||
Channel channel = bootstrap.register().channel();
|
||||
if (channel.config().setOption(UnixChannelOption.SO_REUSEPORT, true)) {
|
||||
bootstrap.option(UnixChannelOption.SO_REUSEPORT, true);
|
||||
} else {
|
||||
// If this occurs, we guessed wrong and reuseport is not available
|
||||
GeyserImpl.getInstance().getLogger().debug("so_reuseport is not available despite version being " + Native.KERNEL_VERSION);
|
||||
success = false;
|
||||
}
|
||||
// Now yeet that channel
|
||||
channel.close();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private static int[] fromString(String input) {
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
package org.geysermc.geyser.network.netty;
|
||||
|
||||
import com.github.steveice10.packetlib.helper.TransportHelper;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
|
@ -39,6 +38,9 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup;
|
|||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.DatagramChannel;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||
import io.netty.incubator.channel.uring.IOUring;
|
||||
import io.netty.incubator.channel.uring.IOUringDatagramChannel;
|
||||
import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import lombok.Getter;
|
||||
import net.jodah.expiringmap.ExpirationPolicy;
|
||||
|
@ -106,7 +108,7 @@ public final class GeyserServer {
|
|||
|
||||
@Getter
|
||||
private final ExpiringMap<InetSocketAddress, InetSocketAddress> proxiedAddresses;
|
||||
private final int listenCount;
|
||||
private int listenCount;
|
||||
|
||||
private ChannelFuture[] bootstrapFutures;
|
||||
|
||||
|
@ -127,8 +129,11 @@ public final class GeyserServer {
|
|||
this.childGroup = TRANSPORT.eventLoopGroupFactory().apply(threadCount);
|
||||
|
||||
this.bootstrap = this.createBootstrap();
|
||||
// setup SO_REUSEPORT if exists
|
||||
Bootstraps.setupBootstrap(this.bootstrap);
|
||||
// setup SO_REUSEPORT if exists - or, if the option does not actually exist, reset listen count
|
||||
// otherwise, we try to bind multiple times which wont work if so_reuseport is not valid
|
||||
if (!Bootstraps.setupBootstrap(this.bootstrap)) {
|
||||
this.listenCount = 1;
|
||||
}
|
||||
|
||||
if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
||||
this.proxiedAddresses = ExpiringMap.builder()
|
||||
|
@ -415,22 +420,35 @@ public final class GeyserServer {
|
|||
}
|
||||
|
||||
private static Transport compatibleTransport() {
|
||||
TransportHelper.TransportMethod transportMethod = TransportHelper.determineTransportMethod();
|
||||
if (transportMethod == TransportHelper.TransportMethod.EPOLL) {
|
||||
if (isClassAvailable("io.netty.incubator.channel.uring.IOUring")
|
||||
&& IOUring.isAvailable()
|
||||
&& Boolean.parseBoolean(System.getProperty("Geyser.io_uring"))) {
|
||||
return new Transport(IOUringDatagramChannel.class, IOUringEventLoopGroup::new);
|
||||
}
|
||||
|
||||
if (isClassAvailable("io.netty.channel.epoll.Epoll") && Epoll.isAvailable()) {
|
||||
return new Transport(EpollDatagramChannel.class, EpollEventLoopGroup::new);
|
||||
}
|
||||
|
||||
if (transportMethod == TransportHelper.TransportMethod.KQUEUE) {
|
||||
if (isClassAvailable("io.netty.channel.kqueue.KQueue") && KQueue.isAvailable()) {
|
||||
return new Transport(KQueueDatagramChannel.class, KQueueEventLoopGroup::new);
|
||||
}
|
||||
|
||||
// if (transportMethod == TransportHelper.TransportMethod.IO_URING) {
|
||||
// return new Transport(IOUringDatagramChannel.class, IOUringEventLoopGroup::new);
|
||||
// }
|
||||
|
||||
return new Transport(NioDatagramChannel.class, NioEventLoopGroup::new);
|
||||
}
|
||||
|
||||
private record Transport(Class<? extends DatagramChannel> datagramChannel, IntFunction<EventLoopGroup> eventLoopGroupFactory) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used so implementations can opt to remove these dependencies if so desired
|
||||
*/
|
||||
private static boolean isClassAvailable(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue