From 17b99a80fe910ba7147aa4f3cd2669b5538422c7 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Wed, 10 Jul 2019 01:34:10 -0500 Subject: [PATCH] Add more packet handlers, allowing upstream to connect to remote --- .../geysermc/connector/GeyserConnector.java | 4 +- ....java => ConnectorServerEventHandler.java} | 10 +- .../network/UpstreamPacketHandler.java | 99 ++++++++++++++ .../network/remote/RemoteJavaServer.java | 26 ++++ .../network/session/GeyserSession.java | 122 ++++++++++++++++++ 5 files changed, 255 insertions(+), 6 deletions(-) rename connector/src/main/java/org/geysermc/connector/network/{listener/ConnectorServerEventListener.java => ConnectorServerEventHandler.java} (79%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/remote/RemoteJavaServer.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 96b05845b..86c8de6bd 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -30,7 +30,7 @@ import org.geysermc.connector.command.GeyserCommandMap; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.console.ConsoleCommandReader; import org.geysermc.connector.console.GeyserLogger; -import org.geysermc.connector.network.listener.ConnectorServerEventListener; +import org.geysermc.connector.network.ConnectorServerEventHandler; import org.geysermc.connector.plugin.GeyserPluginLoader; import org.geysermc.connector.plugin.GeyserPluginManager; @@ -115,7 +115,7 @@ public class GeyserConnector implements Connector { pluginManager.getLoader().loadPlugins(); BedrockServer bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort())); - bedrockServer.setHandler(new ConnectorServerEventListener(this)); + bedrockServer.setHandler(new ConnectorServerEventHandler(this)); bedrockServer.bind().whenComplete((avoid, throwable) -> { if (throwable == null) { logger.info("Started RakNet on " + config.getBedrock().getAddress() + ":" + config.getBedrock().getPort()); diff --git a/connector/src/main/java/org/geysermc/connector/network/listener/ConnectorServerEventListener.java b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java similarity index 79% rename from connector/src/main/java/org/geysermc/connector/network/listener/ConnectorServerEventListener.java rename to connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java index 265e46083..549472ad0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/listener/ConnectorServerEventListener.java +++ b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java @@ -12,21 +12,22 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.listener; +package org.geysermc.connector.network; import com.nukkitx.protocol.bedrock.BedrockPong; import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; import com.nukkitx.protocol.bedrock.BedrockServerSession; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.configuration.GeyserConfiguration; +import org.geysermc.connector.network.session.GeyserSession; import java.net.InetSocketAddress; -public class ConnectorServerEventListener implements BedrockServerEventHandler { +public class ConnectorServerEventHandler implements BedrockServerEventHandler { private GeyserConnector connector; - public ConnectorServerEventListener(GeyserConnector connector) { + public ConnectorServerEventHandler(GeyserConnector connector) { this.connector = connector; } @@ -53,6 +54,7 @@ public class ConnectorServerEventListener implements BedrockServerEventHandler { @Override public void onSessionCreation(BedrockServerSession bedrockServerSession) { - + bedrockServerSession.setLogging(true); + bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession))); } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java new file mode 100644 index 000000000..533ad3790 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -0,0 +1,99 @@ +/* + * GNU LESSER GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * Copyright (C) 2007 Free Software Foundation, Inc. + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + * + * You can view the LICENCE file for details. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network; + +import com.nimbusds.jose.JWSObject; +import com.nukkitx.protocol.bedrock.handler.BedrockPacketHandler; +import com.nukkitx.protocol.bedrock.packet.LoginPacket; +import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; +import com.nukkitx.protocol.bedrock.packet.ResourcePackClientResponsePacket; +import com.nukkitx.protocol.bedrock.packet.ResourcePackStackPacket; +import com.nukkitx.protocol.bedrock.packet.ResourcePacksInfoPacket; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.remote.RemoteJavaServer; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.UUID; + +public class UpstreamPacketHandler implements BedrockPacketHandler { + + private GeyserConnector connector; + private GeyserSession session; + + public UpstreamPacketHandler(GeyserConnector connector, GeyserSession session) { + this.connector = connector; + this.session = session; + } + + @Override + public boolean handle(LoginPacket loginPacket) { + // TODO: Implement support for multiple protocols + if (loginPacket.getProtocolVersion() != GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) { + session.getUpstream().disconnect("Unsupported Bedrock version. Are you running an outdated version?"); + return true; + } + + session.getUpstream().setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); + + try { + JSONObject chainData = (JSONObject) JSONValue.parse(loginPacket.getChainData().array()); + JSONArray chainArray = (JSONArray) chainData.get("chain"); + + Object identityObject = chainArray.get(chainArray.size() - 1); + + JWSObject identity = JWSObject.parse((String) identityObject); + JSONObject extraData = (JSONObject) identity.getPayload().toJSONObject().get("extraData"); + + session.setAuthenticationData(extraData.getAsString("displayName"), UUID.fromString(extraData.getAsString("identity")), extraData.getAsString("XUID")); + } catch (Exception ex) { + session.getUpstream().disconnect("An internal error occurred when connecting to this server."); + ex.printStackTrace(); + return true; + } + + PlayStatusPacket playStatus = new PlayStatusPacket(); + playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); + session.getUpstream().sendPacketImmediately(playStatus); + + ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket(); + session.getUpstream().sendPacketImmediately(resourcePacksInfo); + return true; + } + + @Override + public boolean handle(ResourcePackClientResponsePacket textPacket) { + switch (textPacket.getStatus()) { + case COMPLETED: + // Start connecting to remote server + RemoteJavaServer remoteServer = new RemoteJavaServer(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort()); + session.connect(remoteServer); + connector.getLogger().info("Player connected with " + session.getAuthenticationData().getName()); + break; + case HAVE_ALL_PACKS: + ResourcePackStackPacket stack = new ResourcePackStackPacket(); + stack.setExperimental(false); + stack.setForcedToAccept(false); + session.getUpstream().sendPacketImmediately(stack); + break; + default: + session.getUpstream().disconnect("disconnectionScreen.resourcePack"); + break; + } + return true; + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/remote/RemoteJavaServer.java b/connector/src/main/java/org/geysermc/connector/network/remote/RemoteJavaServer.java new file mode 100644 index 000000000..5689d77cb --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/remote/RemoteJavaServer.java @@ -0,0 +1,26 @@ +/* + * GNU LESSER GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * Copyright (C) 2007 Free Software Foundation, Inc. + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + * + * You can view the LICENCE file for details. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.remote; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class RemoteJavaServer { + + private String address; + private int port; +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java new file mode 100644 index 000000000..61f932b9e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -0,0 +1,122 @@ +/* + * GNU LESSER GENERAL PUBLIC LICENSE + * Version 3, 29 June 2007 + * + * Copyright (C) 2007 Free Software Foundation, Inc. + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + * + * You can view the LICENCE file for details. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.session; + +import com.github.steveice10.mc.protocol.MinecraftProtocol; +import com.github.steveice10.packetlib.Client; +import com.github.steveice10.packetlib.event.session.ConnectedEvent; +import com.github.steveice10.packetlib.event.session.DisconnectedEvent; +import com.github.steveice10.packetlib.event.session.PacketReceivedEvent; +import com.github.steveice10.packetlib.event.session.SessionAdapter; +import com.github.steveice10.packetlib.tcp.TcpSessionFactory; +import com.nukkitx.network.util.DisconnectReason; +import com.nukkitx.protocol.PlayerSession; +import com.nukkitx.protocol.bedrock.BedrockServerSession; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.remote.RemoteJavaServer; + +import java.util.UUID; + +public class GeyserSession implements PlayerSession { + + private GeyserConnector connector; + + @Getter + private RemoteJavaServer remoteServer; + + @Getter + private BedrockServerSession upstream; + + @Getter + private Client downstream; + + @Getter + private AuthenticationData authenticationData; + + private boolean closed; + + public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { + this.connector = connector; + this.upstream = bedrockServerSession; + } + + public void connect(RemoteJavaServer remoteServer) { + MinecraftProtocol protocol = new MinecraftProtocol(authenticationData.getName()); + downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); + downstream.getSession().addListener(new SessionAdapter() { + + @Override + public void connected(ConnectedEvent event) { + connector.getLogger().info(authenticationData.getName() + " has connected to remote java server on address " + remoteServer.getAddress()); + } + + @Override + public void disconnected(DisconnectedEvent event) { + connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress()); + upstream.disconnect(event.getReason()); + } + + @Override + public void packetReceived(PacketReceivedEvent event) { + // TODO: Implement translator code here + } + }); + + downstream.getSession().connect(); + this.remoteServer = remoteServer; + } + + public void disconnect(String reason) { + if (!closed) { + downstream.getSession().disconnect(reason); + upstream.disconnect(reason); + } + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public void close() { + disconnect("Server closed."); + } + + @Override + public void onDisconnect(DisconnectReason disconnectReason) { + downstream.getSession().disconnect("Disconnected from server. Reason: " + disconnectReason); + } + + @Override + public void onDisconnect(String reason) { + downstream.getSession().disconnect("Disconnected from server. Reason: " + reason); + } + + public void setAuthenticationData(String name, UUID uuid, String xboxUUID) { + authenticationData = new AuthenticationData(name, uuid, xboxUUID); + } + + @Getter + @AllArgsConstructor + public class AuthenticationData { + + private String name; + private UUID uuid; + private String xboxUUID; + } +} \ No newline at end of file