From 73633f7811f75f15ed9f5703a793b00f7bfee9e0 Mon Sep 17 00:00:00 2001 From: AlexProgrammerDE <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:49:39 +0100 Subject: [PATCH] Implement session restructure mcpl PR --- .../platform/spigot/GeyserSpigotInjector.java | 7 +- .../java/org/geysermc/geyser/GeyserImpl.java | 1 - .../netty/LocalChannelWithRemoteAddress.java | 7 +- .../geyser/network/netty/LocalSession.java | 149 ++++-------------- .../geyser/session/DownstreamSession.java | 4 +- .../geyser/session/GeyserSession.java | 21 ++- gradle/libs.versions.toml | 4 +- 7 files changed, 57 insertions(+), 136 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 9f7e21579d6..3098ef0e0d6 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.platform.spigot; +import org.geysermc.mcprotocollib.protocol.MinecraftConstants; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer; import io.netty.bootstrap.ServerBootstrap; @@ -176,9 +177,9 @@ private ChannelInitializer getChildHandler(GeyserBootstrap bootstrap, C */ private void workAroundWeirdBug(GeyserBootstrap bootstrap) { MinecraftProtocol protocol = new MinecraftProtocol(); - LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(), - bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, - InetAddress.getLoopbackAddress().getHostAddress(), protocol, Runnable::run); + LocalSession session = new LocalSession(this.serverSocketAddress, InetAddress.getLoopbackAddress().getHostAddress(), protocol, Runnable::run); + session.setFlag(MinecraftConstants.CLIENT_HOST, bootstrap.getGeyserConfig().getRemote().address()); + session.setFlag(MinecraftConstants.CLIENT_PORT, bootstrap.getGeyserConfig().getRemote().port()); session.connect(); } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 065c1f0cc63..728afb690a8 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -101,7 +101,6 @@ import org.geysermc.geyser.util.NewsHandler; import org.geysermc.geyser.util.VersionCheckUtils; import org.geysermc.geyser.util.WebUtils; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; import java.io.File; import java.io.FileWriter; diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java index ac2b6898a71..dacb4de69d0 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java @@ -28,18 +28,19 @@ import io.netty.channel.local.LocalChannel; import java.net.InetSocketAddress; +import java.net.SocketAddress; /** * Client -> server storing the spoofed remote address. */ public class LocalChannelWithRemoteAddress extends LocalChannel { - private InetSocketAddress spoofedAddress; + private SocketAddress spoofedAddress; - public InetSocketAddress spoofedRemoteAddress() { + public SocketAddress spoofedRemoteAddress() { return spoofedAddress; } - public void spoofedRemoteAddress(InetSocketAddress socketAddress) { + public void spoofedRemoteAddress(SocketAddress socketAddress) { this.spoofedAddress = socketAddress; } } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 3b86a0bf9f0..2c7b001d2e4 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -27,151 +27,66 @@ import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.DefaultEventLoopGroup; +import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.unix.PreferredDirectByteBufAllocator; -import io.netty.handler.codec.haproxy.HAProxyCommand; -import io.netty.handler.codec.haproxy.HAProxyMessage; -import io.netty.handler.codec.haproxy.HAProxyMessageEncoder; -import io.netty.handler.codec.haproxy.HAProxyProtocolVersion; -import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol; -import io.netty.handler.timeout.ReadTimeoutHandler; -import io.netty.handler.timeout.WriteTimeoutHandler; -import io.netty.util.concurrent.DefaultThreadFactory; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.mcprotocollib.network.BuiltinFlags; -import org.geysermc.mcprotocollib.network.codec.PacketCodecHelper; +import org.geysermc.mcprotocollib.network.helper.NettyHelper; +import org.geysermc.mcprotocollib.network.net.MinecraftChannelInitializer; +import org.geysermc.mcprotocollib.network.net.NetClientSession; import org.geysermc.mcprotocollib.network.packet.PacketProtocol; -import org.geysermc.mcprotocollib.network.tcp.FlushHandler; -import org.geysermc.mcprotocollib.network.tcp.TcpFlowControlHandler; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketCodec; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketCompression; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketEncryptor; -import org.geysermc.mcprotocollib.network.tcp.TcpPacketSizer; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; -import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; /** * Manages a Minecraft Java session over our LocalChannel implementations. */ -public final class LocalSession extends TcpSession { - private static DefaultEventLoopGroup DEFAULT_EVENT_LOOP_GROUP; +public final class LocalSession extends NetClientSession { private static PreferredDirectByteBufAllocator PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR = null; - private final SocketAddress targetAddress; - private final String clientIp; - private final PacketCodecHelper codecHelper; + private final SocketAddress spoofedRemoteAddress; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) { - super(host, port, protocol, packetHandlerExecutor); - this.targetAddress = targetAddress; - this.clientIp = clientIp; - this.codecHelper = protocol.createHelper(); + public LocalSession(SocketAddress targetAddress, String clientIp, PacketProtocol protocol, Executor packetHandlerExecutor) { + super(targetAddress, null, protocol, null, packetHandlerExecutor); + this.spoofedRemoteAddress = new InetSocketAddress(clientIp, 0); } @Override - public void connect(boolean wait, boolean transferring) { - if (this.disconnected) { - throw new IllegalStateException("Connection has already been disconnected."); - } - - if (DEFAULT_EVENT_LOOP_GROUP == null) { - DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup(new DefaultThreadFactory(this.getClass(), true)); - Runtime.getRuntime().addShutdownHook(new Thread( - () -> DEFAULT_EVENT_LOOP_GROUP.shutdownGracefully(100, 500, TimeUnit.MILLISECONDS))); - } - - final Bootstrap bootstrap = new Bootstrap(); - bootstrap.channel(LocalChannelWithRemoteAddress.class); - bootstrap.handler(new ChannelInitializer() { - @Override - public void initChannel(@NonNull LocalChannelWithRemoteAddress channel) { - channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0)); - PacketProtocol protocol = getPacketProtocol(); - protocol.newClientSession(LocalSession.this, transferring); - - ChannelPipeline pipeline = channel.pipeline(); - - addHAProxySupport(pipeline); - - pipeline.addLast("read-timeout", new ReadTimeoutHandler(getFlag(BuiltinFlags.READ_TIMEOUT, 30))); - pipeline.addLast("write-timeout", new WriteTimeoutHandler(getFlag(BuiltinFlags.WRITE_TIMEOUT, 0))); - - pipeline.addLast("encryption", new TcpPacketEncryptor()); - pipeline.addLast("sizer", new TcpPacketSizer(protocol.getPacketHeader(), getCodecHelper())); - pipeline.addLast("compression", new TcpPacketCompression(getCodecHelper())); - - pipeline.addLast("flow-control", new TcpFlowControlHandler()); - pipeline.addLast("codec", new TcpPacketCodec(LocalSession.this, true)); - pipeline.addLast("flush-handler", new FlushHandler()); - pipeline.addLast("manager", LocalSession.this); - } - }).group(DEFAULT_EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getFlag(BuiltinFlags.CLIENT_CONNECT_TIMEOUT, 30) * 1000); + protected ChannelFactory getChannelFactory() { + return new ReflectiveChannelFactory<>(LocalChannelWithRemoteAddress.class); + } + @Override + protected void setOptions(Bootstrap bootstrap) { if (PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR != null) { bootstrap.option(ChannelOption.ALLOCATOR, PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR); } + } - bootstrap.remoteAddress(targetAddress); - - CompletableFuture handleFuture = new CompletableFuture<>(); - bootstrap.connect().addListener((futureListener) -> { - if (!futureListener.isSuccess()) { - exceptionCaught(null, futureListener.cause()); - } + @Override + protected ChannelHandler getChannelHandler() { + return new MinecraftChannelInitializer<>(channel -> { + PacketProtocol protocol = getPacketProtocol(); + protocol.newClientSession(LocalSession.this); - handleFuture.complete(null); - }); + return LocalSession.this; + }, true) { + @Override + public void initChannel(@NonNull Channel channel) throws Exception { + ((LocalChannelWithRemoteAddress) channel).spoofedRemoteAddress(spoofedRemoteAddress); - if (wait) { - handleFuture.join(); - } - } + NettyHelper.initializeHAProxySupport(LocalSession.this, channel); - @Override - public MinecraftCodecHelper getCodecHelper() { - return (MinecraftCodecHelper) this.codecHelper; + super.initChannel(channel); + } + }; } - // TODO duplicate code - private void addHAProxySupport(ChannelPipeline pipeline) { - InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); - if (clientAddress != null) { - pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() { - @Override - public void channelActive(@NonNull ChannelHandlerContext ctx) throws Exception { - HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6; - InetSocketAddress remoteAddress; - if (ctx.channel().remoteAddress() instanceof InetSocketAddress) { - remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - } else { - remoteAddress = new InetSocketAddress(host, port); - } - ctx.channel().writeAndFlush(new HAProxyMessage( - HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol, - clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(), - clientAddress.getPort(), remoteAddress.getPort() - )); - ctx.pipeline().remove(this); - ctx.pipeline().remove("proxy-protocol-encoder"); - super.channelActive(ctx); - } - }); - pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE); - } - } - /** * Should only be called when direct ByteBufs should be preferred. At this moment, this should only be called on BungeeCord. */ diff --git a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java index 8845cdbeae0..a619614e095 100644 --- a/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/DownstreamSession.java @@ -28,14 +28,14 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.mcprotocollib.network.ClientSession; import org.geysermc.mcprotocollib.network.packet.Packet; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; @Getter @RequiredArgsConstructor public class DownstreamSession { - private final TcpSession session; + private final ClientSession session; public void sendPacket(@NonNull Packet packet) { this.session.send(packet); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index b4a8e6203f8..f503f8d96d9 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -186,15 +186,17 @@ import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.network.BuiltinFlags; +import org.geysermc.mcprotocollib.network.ClientSession; +import org.geysermc.mcprotocollib.network.NetworkConstants; import org.geysermc.mcprotocollib.network.Session; import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent; import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent; import org.geysermc.mcprotocollib.network.event.session.PacketErrorEvent; import org.geysermc.mcprotocollib.network.event.session.PacketSendingEvent; import org.geysermc.mcprotocollib.network.event.session.SessionAdapter; +import org.geysermc.mcprotocollib.network.net.NetClientSession; +import org.geysermc.mcprotocollib.network.net.NetSession; import org.geysermc.mcprotocollib.network.packet.Packet; -import org.geysermc.mcprotocollib.network.tcp.TcpClientSession; -import org.geysermc.mcprotocollib.network.tcp.TcpSession; import org.geysermc.mcprotocollib.protocol.MinecraftConstants; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.data.ProtocolState; @@ -949,15 +951,17 @@ private void connectDownstream() { // Start ticking tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); - TcpSession downstream; + ClientSession downstream; if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP - downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), - geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, tickEventLoop); + downstream = new LocalSession(geyser.getBootstrap().getSocketAddress(), + upstream.getAddress().getAddress().getHostAddress(), + this.protocol, tickEventLoop); + downstream.setFlag(MinecraftConstants.CLIENT_HOST, this.remoteServer.address()); + downstream.setFlag(MinecraftConstants.CLIENT_PORT, this.remoteServer.port()); this.downstream = new DownstreamSession(downstream); } else { - downstream = new TcpClientSession(this.remoteServer.address(), this.remoteServer.port(), "0.0.0.0", 0, this.protocol, null, tickEventLoop); + downstream = new NetClientSession(new InetSocketAddress(this.remoteServer.address(), this.remoteServer.port()), null, this.protocol, null, tickEventLoop); this.downstream = new DownstreamSession(downstream); boolean resolveSrv = false; @@ -1159,7 +1163,8 @@ public void packetError(PacketErrorEvent event) { setDaylightCycle(true); } - downstream.connect(false, loginEvent.transferring()); + downstream.setFlag(BuiltinFlags.CLIENT_TRANSFERRING, loginEvent.transferring()); + downstream.connect(false); } public void disconnect(String reason) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ebd378d572e..18ddd96c0e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241203.200249-19" protocol-codec = "3.0.0.Beta5-20241203.200249-19" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21.2-20241127.160724-5" +mcprotocollib = "5c2249d" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -123,7 +123,7 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } minecraftauth = { group = "net.raphimc", name = "MinecraftAuth", version.ref = "minecraftauth" } -mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" } +mcprotocollib = { group = "com.github.AlexProgrammerDE", name = "MCProtocolLib", version.ref = "mcprotocollib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" }