From a4deeb9824baa3c53fa5f863c848771e71f3b35d Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 28 Dec 2024 16:15:31 -0500 Subject: [PATCH] configure: add ipv4 mode This is difficult since libnet and java/net need to agree on whether preferIPv4Stack is set, or else libnet will create sockets java/net can't use. Work around this by setting the launcher vmargs, as libnet is already loaded by the time we get to main(). --- .../runelite/launcher/ConfigurationFrame.java | 24 +++++++++ .../java/net/runelite/launcher/Launcher.java | 13 +++-- .../runelite/launcher/LauncherSettings.java | 3 ++ .../net/runelite/launcher/PackrConfig.java | 54 ++++++++++++++----- 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/runelite/launcher/ConfigurationFrame.java b/src/main/java/net/runelite/launcher/ConfigurationFrame.java index a633e6bf..24856018 100644 --- a/src/main/java/net/runelite/launcher/ConfigurationFrame.java +++ b/src/main/java/net/runelite/launcher/ConfigurationFrame.java @@ -32,6 +32,8 @@ import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.swing.BorderFactory; @@ -57,6 +59,7 @@ public class ConfigurationFrame extends JFrame private final JCheckBox chkboxSkipTlsVerification; private final JCheckBox chkboxNoUpdates; private final JCheckBox chkboxSafemode; + private final JCheckBox chkboxIpv4; private final JTextField txtScale; private final JTextArea txtClientArguments; private final JTextArea txtJvmArguments; @@ -119,6 +122,12 @@ private ConfigurationFrame(LauncherSettings settings) Boolean.TRUE.equals(settings.safemode) )); + topPanel.add(chkboxIpv4 = checkbox( + "IPv4", + "Prefer IPv4 over IPv6", + Boolean.TRUE.equals(settings.ipv4) + )); + pane.add(topPanel); var midPanel = new JPanel(); @@ -198,6 +207,7 @@ private void save(ActionEvent l) settings.skipTlsVerification = chkboxSkipTlsVerification.isSelected(); settings.noupdates = chkboxNoUpdates.isSelected(); settings.safemode = chkboxSafemode.isSelected(); + settings.ipv4 = chkboxIpv4.isSelected(); var t = txtScale.getText(); settings.scale = null; @@ -227,6 +237,20 @@ private void save(ActionEvent l) LauncherSettings.saveSettings(settings); + // IPv4 change requires patching packr config + PackrConfig.patch(config -> + { + List vmArgs = (List) config.computeIfAbsent("vmArgs", k -> new ArrayList<>()); + if (settings.ipv4) + { + vmArgs.add("-Djava.net.preferIPv4Stack=true"); + } + else + { + vmArgs.remove("-Djava.net.preferIPv4Stack=true"); + } + }); + log.info("Updated launcher configuration:" + System.lineSeparator() + "{}", settings.configurationStr()); dispose(); diff --git a/src/main/java/net/runelite/launcher/Launcher.java b/src/main/java/net/runelite/launcher/Launcher.java index 12f6a415..5bacdf2d 100644 --- a/src/main/java/net/runelite/launcher/Launcher.java +++ b/src/main/java/net/runelite/launcher/Launcher.java @@ -262,7 +262,7 @@ public static void main(String[] args) if (postInstall) { - postInstall(); + postInstall(settings); return; } @@ -343,7 +343,7 @@ public static void main(String[] args) } // update packr vmargs to the launcher vmargs from bootstrap. - PackrConfig.updateLauncherArgs(bootstrap); + PackrConfig.updateLauncherArgs(bootstrap, settings); // Determine artifacts for this OS List artifacts = Arrays.stream(bootstrap.getArtifacts()) @@ -593,6 +593,11 @@ private static List getJvmArgs(LauncherSettings settings) { var args = new ArrayList<>(settings.jvmArguments); + if (settings.ipv4) + { + args.add("-Djava.net.preferIPv4Stack=true"); + } + var envArgs = System.getenv("RUNELITE_VMARGS"); if (!Strings.isNullOrEmpty(envArgs)) { @@ -921,7 +926,7 @@ static boolean isJava17() return Runtime.version().feature() >= 16; } - private static void postInstall() + private static void postInstall(LauncherSettings settings) { Bootstrap bootstrap; try @@ -934,7 +939,7 @@ private static void postInstall() return; } - PackrConfig.updateLauncherArgs(bootstrap); + PackrConfig.updateLauncherArgs(bootstrap, settings); log.info("Performed postinstall steps"); } diff --git a/src/main/java/net/runelite/launcher/LauncherSettings.java b/src/main/java/net/runelite/launcher/LauncherSettings.java index b7b7bef9..8d5e2484 100644 --- a/src/main/java/net/runelite/launcher/LauncherSettings.java +++ b/src/main/java/net/runelite/launcher/LauncherSettings.java @@ -66,6 +66,7 @@ class LauncherSettings boolean skipTlsVerification; boolean noupdates; boolean safemode; + boolean ipv4; @Nullable Double scale; List clientArguments = Collections.emptyList(); @@ -141,6 +142,7 @@ String configurationStr() " skip tls verification: {}" + System.lineSeparator() + " noupdates: {}" + System.lineSeparator() + " safe mode: {}" + System.lineSeparator() + + " ipv4: {}" + System.lineSeparator() + " scale: {}" + System.lineSeparator() + " client arguments: {}" + System.lineSeparator() + " jvm arguments: {}" + System.lineSeparator() + @@ -152,6 +154,7 @@ String configurationStr() skipTlsVerification, noupdates, safemode, + ipv4, scale == null ? "system" : scale, clientArguments.isEmpty() ? "none" : clientArguments, jvmArguments.isEmpty() ? "none" : jvmArguments, diff --git a/src/main/java/net/runelite/launcher/PackrConfig.java b/src/main/java/net/runelite/launcher/PackrConfig.java index 44fc1b7a..68aa7c8f 100644 --- a/src/main/java/net/runelite/launcher/PackrConfig.java +++ b/src/main/java/net/runelite/launcher/PackrConfig.java @@ -39,7 +39,11 @@ import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Map; +import java.util.function.Consumer; import lombok.extern.slf4j.Slf4j; import net.runelite.launcher.beans.Bootstrap; @@ -47,7 +51,35 @@ class PackrConfig { // Update the packr config - static void updateLauncherArgs(Bootstrap bootstrap) + static void updateLauncherArgs(Bootstrap bootstrap, LauncherSettings settings) + { + String[] bootstrapVmArgs = getVmArgs(bootstrap); + if (bootstrapVmArgs == null || bootstrapVmArgs.length == 0) + { + log.warn("Launcher args are empty"); + return; + } + + List vmArgs = new ArrayList<>(Arrays.asList(bootstrapVmArgs)); + + // java.net.preferIPv4Stack needs to be set prior to libnet *loading* (it is read in net_util.c JNI_OnLoad). + // Failure to keep preferIPv4Stack consistent between libnet and java/net results in disagreements over + // which socket types can be used. + if (settings.ipv4) + { + vmArgs.add("-Djava.net.preferIPv4Stack=true"); + } + + Map env = getEnv(bootstrap); + + patch(config -> + { + config.put("vmArgs", vmArgs); + config.put("env", env); + }); + } + + static void patch(Consumer configConsumer) { var os = OS.getOs(); if (os != OS.OSType.Windows && os != OS.OSType.MacOS) @@ -71,7 +103,7 @@ static void updateLauncherArgs(Bootstrap bootstrap) } catch (IOException | JsonIOException | JsonSyntaxException e) { - log.warn("error deserializing packr vm args!", e); + log.warn("error deserializing launcher vm args!", e); return; } @@ -79,19 +111,11 @@ static void updateLauncherArgs(Bootstrap bootstrap) { // this can't happen when run from the launcher, because an invalid packr config would prevent the launcher itself // from starting. But could happen if the jar launcher was run separately. - log.warn("packr config is null!"); - return; - } - - String[] argsArr = getArgs(bootstrap); - if (argsArr == null || argsArr.length == 0) - { - log.warn("Launcher args are empty"); + log.warn("launcher config is null!"); return; } - config.put("vmArgs", argsArr); - config.put("env", getEnv(bootstrap)); + configConsumer.accept(config); try { @@ -117,14 +141,16 @@ static void updateLauncherArgs(Bootstrap bootstrap) log.debug("atomic move not supported", ex); Files.move(tmpFile.toPath(), configFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } + + log.debug("patched packr config"); } catch (IOException e) { - log.warn("error updating packr vm args!", e); + log.warn("error updating launcher vm args!", e); } } - private static String[] getArgs(Bootstrap bootstrap) + private static String[] getVmArgs(Bootstrap bootstrap) { return Launcher.isJava17() ? getArgsJvm17(bootstrap) : getArgsJvm11(bootstrap); }