From abaa2f3a0e608f90699f906293d9ee09387697a2 Mon Sep 17 00:00:00 2001 From: ME1312 Date: Wed, 9 Jan 2019 12:37:02 -0500 Subject: [PATCH] Add PID termination in Java 8 Some trickery was applied, but its okay since Java 9 has proper API methods for this stuff anyway --- SubServers.Bungee/pom.xml | 6 ++ .../SubServers/Bungee/Host/Executable.java | 59 +++++++++++++++++++ .../Host/Internal/InternalSubCreator.java | 15 +---- .../Host/Internal/InternalSubServer.java | 7 +-- .../SubServers/Client/Sponge/SubCommand.java | 2 +- SubServers.Host/pom.xml | 8 ++- .../Host/Executable/Executable.java | 59 +++++++++++++++++++ .../Host/Executable/SubCreator.java | 15 +---- .../SubServers/Host/Executable/SubServer.java | 7 +-- 9 files changed, 138 insertions(+), 40 deletions(-) diff --git a/SubServers.Bungee/pom.xml b/SubServers.Bungee/pom.xml index c53b9911..1b7879c9 100644 --- a/SubServers.Bungee/pom.xml +++ b/SubServers.Bungee/pom.xml @@ -27,6 +27,12 @@ 1.9-SNAPSHOT provided + + net.java.dev.jna + jna-platform + 5.2.0 + compile + org.msgpack msgpack-core diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java index f60e2f07..2ce75a01 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java @@ -1,6 +1,11 @@ package net.ME1312.SubServers.Bungee.Host; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinNT; + import java.io.File; +import java.lang.reflect.Field; /** * Executable String Handler Class @@ -27,4 +32,58 @@ public class Executable { } return cmd; } + + /** + * Get the PID of a currently running process + * + * @param process Process + * @return Process ID + */ + public static Long pid(Process process) { + if (process.isAlive()) { + try { + return (long) Process.class.getDeclaredMethod("pid").invoke(process); + } catch (Throwable ex) { + try { + if (process.getClass().getName().equals("java.lang.Win32Process") || process.getClass().getName().equals("java.lang.ProcessImpl")) { + Field f = process.getClass().getDeclaredField("handle"); + f.setAccessible(true); + long handle = f.getLong(process); + f.setAccessible(false); + + Kernel32 k32 = Kernel32.INSTANCE; + WinNT.HANDLE nt = new WinNT.HANDLE(); + nt.setPointer(Pointer.createConstant(handle)); + return (long) k32.GetProcessId(nt); + } else if (process.getClass().getName().equals("java.lang.UNIXProcess")) { + Field f = process.getClass().getDeclaredField("pid"); + f.setAccessible(true); + Object response = f.get(process); + f.setAccessible(false); + + if (response instanceof Number) return ((Number) response).longValue(); + } + } catch (Throwable e) {} + } + } + return null; + } + + /** + * Terminate a currently running process + * + * @param process Process + */ + public static void terminate(Process process) { + if (process.isAlive()) { + if (System.getProperty("os.name").toLowerCase().startsWith("windows")) { + Long pid = pid(process); + if (pid != null) try { + Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", pid.toString()}); + terminator.waitFor(); + } catch (Throwable e) {} + } + if (process.isAlive()) process.destroyForcibly(); + } + } } diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java index fa566b62..c3eacaff 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java @@ -358,20 +358,9 @@ public class InternalSubCreator extends SubCreator { @Override public void terminate(String name) { if (this.thread.keySet().contains(name.toLowerCase())) { - boolean success = false; - if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { - Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(this.thread.get(name.toLowerCase()).process))}); - terminator.waitFor(); - if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); - success = true; - } catch (Exception e) {} - if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive()) { - this.thread.get(name.toLowerCase()).process.destroyForcibly(); - success = true; - } - - if (!success && this.thread.get(name.toLowerCase()).isAlive()) { + Executable.terminate(this.thread.get(name.toLowerCase()).process); + } else if (this.thread.get(name.toLowerCase()).isAlive()) { this.thread.get(name.toLowerCase()).interrupt(); this.thread.remove(name.toLowerCase()); } diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java index 35a13d63..d6eb3223 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java @@ -221,12 +221,7 @@ public class InternalSubServer extends SubServerContainer { host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { allowrestart = false; - if (process != null && process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { - Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(process))}); - terminator.waitFor(); - if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); - } catch (Exception e) {} - if (process != null && process.isAlive()) process.destroyForcibly(); + if (process != null && process.isAlive()) Executable.terminate(process); return true; } else return false; } else return false; diff --git a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java index 8140e126..2cc58bd5 100644 --- a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java +++ b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java @@ -766,7 +766,7 @@ public final class SubCommand implements CommandExecutor { return CommandResult.builder().successCount(0).build(); } } else { - sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers","Command.Generic.Usage").replace("$str$", "/sub stop "))); + sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers","Command.Generic.Usage").replace("$str$", "/sub restart "))); return CommandResult.builder().successCount(0).build(); } } else { diff --git a/SubServers.Host/pom.xml b/SubServers.Host/pom.xml index d8353127..dd71c901 100644 --- a/SubServers.Host/pom.xml +++ b/SubServers.Host/pom.xml @@ -20,7 +20,13 @@ net.ME1312.Galaxi GalaxiEngine - 19w02d + 19w02e + compile + + + net.java.dev.jna + jna-platform + 5.2.0 compile diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java index d9fe3a13..637d9641 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java @@ -1,6 +1,11 @@ package net.ME1312.SubServers.Host.Executable; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinNT; + import java.io.File; +import java.lang.reflect.Field; /** * Executable String Handler Class @@ -27,4 +32,58 @@ public class Executable { } return cmd; } + + /** + * Get the PID of a currently running process + * + * @param process Process + * @return Process ID + */ + public static Long pid(Process process) { + if (process.isAlive()) { + try { + return (long) Process.class.getDeclaredMethod("pid").invoke(process); + } catch (Throwable ex) { + try { + if (process.getClass().getName().equals("java.lang.Win32Process") || process.getClass().getName().equals("java.lang.ProcessImpl")) { + Field f = process.getClass().getDeclaredField("handle"); + f.setAccessible(true); + long handle = f.getLong(process); + f.setAccessible(false); + + Kernel32 k32 = Kernel32.INSTANCE; + WinNT.HANDLE nt = new WinNT.HANDLE(); + nt.setPointer(Pointer.createConstant(handle)); + return (long) k32.GetProcessId(nt); + } else if (process.getClass().getName().equals("java.lang.UNIXProcess")) { + Field f = process.getClass().getDeclaredField("pid"); + f.setAccessible(true); + Object response = f.get(process); + f.setAccessible(false); + + if (response instanceof Number) return ((Number) response).longValue(); + } + } catch (Throwable e) {} + } + } + return null; + } + + /** + * Terminate a currently running process + * + * @param process Process + */ + public static void terminate(Process process) { + if (process.isAlive()) { + if (System.getProperty("os.name").toLowerCase().startsWith("windows")) { + Long pid = pid(process); + if (pid != null) try { + Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", pid.toString()}); + terminator.waitFor(); + } catch (Throwable e) {} + } + if (process.isAlive()) process.destroyForcibly(); + } + } } diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java index 5d336707..988fb8af 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java @@ -382,20 +382,9 @@ public class SubCreator { public void terminate(String name) { if (this.thread.keySet().contains(name.toLowerCase())) { - boolean success = false; - if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { - Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(this.thread.get(name.toLowerCase()).process))}); - terminator.waitFor(); - if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); - success = true; - } catch (Exception e) {} - if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive()) { - this.thread.get(name.toLowerCase()).process.destroyForcibly(); - success = true; - } - - if (!success && this.thread.get(name.toLowerCase()).isAlive()) { + Executable.terminate(this.thread.get(name.toLowerCase()).process); + } else if (this.thread.get(name.toLowerCase()).isAlive()) { this.thread.get(name.toLowerCase()).interrupt(); this.thread.remove(name.toLowerCase()); } diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java index dbb256fb..bf9f31a5 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java @@ -168,12 +168,7 @@ public class SubServer { */ public void terminate() { allowrestart = false; - if (process != null && process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { - Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(process))}); - terminator.waitFor(); - if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); - } catch (Exception e) {} - if (process != null && process.isAlive()) process.destroyForcibly(); + if (process != null && process.isAlive()) Executable.terminate(process); } /**