Mercurial > hg > thermostat-ng > agent
changeset 2678:259b1bc3fb64
Add thread to command channel to watch when the agent dies, and then abort the
command channel process. This is only running on Windows.
Windows child processes do not otherwise die when the parent dies.
Reviewed-by: jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/023287.html
line wrap: on
line diff
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMain.java Thu May 25 13:40:02 2017 -0400 +++ b/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMain.java Tue May 30 16:30:17 2017 -0400 @@ -43,6 +43,7 @@ import com.redhat.thermostat.agent.ipc.client.ClientIPCService; import com.redhat.thermostat.agent.ipc.client.ClientIPCServiceFactory; import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; +import com.redhat.thermostat.common.portability.ProcessWatcher; import com.redhat.thermostat.shared.config.NativeLibraryResolver; import com.redhat.thermostat.shared.config.OS; import com.redhat.thermostat.shared.config.SSLConfiguration; @@ -52,7 +53,11 @@ static final String IPC_SERVER_NAME = "command-channel"; static final String CONFIG_FILE_PROP = "ipcConfigFile"; - + + private static final int HOSTNAME_ARG_POS = 0; + private static final int HOSTPORT_ARG_POS = 1; + private static final int PARENT_PID_ARG_POS = 2; + private static SSLConfigurationParser sslConfParser = new SSLConfigurationParser(); private static ServerCreator serverCreator = new ServerCreator(); private static ShutdownHookHandler shutdownHandler = new ShutdownHookHandler(); @@ -62,13 +67,13 @@ // TODO Add some keep alive check public static void main(String[] args) throws IOException { - if (args.length != 2) { - throw new IOException("usage: thermostat-command-channel <hostname> <port>"); + if (args.length != 2 && args.length != 3) { + throw new IOException("usage: thermostat-command-channel <hostname> <port> [<parent pid>]"); } - String hostname = args[0]; + String hostname = args[HOSTNAME_ARG_POS]; Integer port; try { - port = Integer.valueOf(args[1]); + port = Integer.valueOf(args[HOSTPORT_ARG_POS]); } catch (NumberFormatException e) { throw new IOException("Port number must be a valid integer"); } @@ -89,7 +94,22 @@ } // Connect to IPC server IPCMessageChannel channel = ipcService.connectToServer(IPC_SERVER_NAME); - + + + // if there's a parent pid, watch for it to exit and then shutdown. + final int parentPid = (args.length == 3) ? Integer.parseInt(args[PARENT_PID_ARG_POS]) : 0; + final int SLEEP_TIME_MS = 5000; // 5 seconds between checks + if (parentPid > 0) { + final ProcessWatcher watcher = new ProcessWatcher(parentPid, SLEEP_TIME_MS) { + @Override + public void onProcessExit() { + // tell myself to exit + System.exit(1); + } + }; + watcher.start(); + } + try { // Notify server has started sendMessage(channel, CommandChannelConstants.SERVER_STARTED_TOKEN);
--- a/agent/command/pom.xml Thu May 25 13:40:02 2017 -0400 +++ b/agent/command/pom.xml Tue May 30 16:30:17 2017 -0400 @@ -131,6 +131,43 @@ </instructions> </configuration> </plugin> + + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy</id> + <phase>generate-resources</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <overwrite>true</overwrite> + <outputDirectory>${project.build.directory}</outputDirectory> + <resources> + <resource> + <directory>../../common/portability/target</directory> + <includes> + <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include> + </includes> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <systemPropertyVariables> + <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome> + </systemPropertyVariables> + </configuration> + </plugin> </plugins> </build>
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java Thu May 25 13:40:02 2017 -0400 +++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java Tue May 30 16:30:17 2017 -0400 @@ -50,6 +50,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import com.redhat.thermostat.common.portability.PortableProcessFactory; import com.redhat.thermostat.agent.command.ConfigurationServer; import com.redhat.thermostat.agent.command.ReceiverRegistry; import com.redhat.thermostat.agent.command.RequestReceiver; @@ -219,7 +220,7 @@ ? new String[]{ binPath.getAbsolutePath() + File.separator + CMD_NAME, hostname, String.valueOf(port), ipcConfig.getAbsolutePath() } : new String[] { "cmd", "/c", binPath.getAbsolutePath() + File.separator + CMD_NAME + ".cmd", hostname, - String.valueOf(port), ipcConfig.getAbsolutePath() }; + String.valueOf(port), ipcConfig.getAbsolutePath(), "" + PortableProcessFactory.getInstance().getCurrentProcessPid()}; ProcessBuilder builder = new ProcessBuilder(processArgs); // This has the problem of some messages/Exceptions not
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java Thu May 25 13:40:02 2017 -0400 +++ b/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java Tue May 30 16:30:17 2017 -0400 @@ -58,6 +58,7 @@ import java.util.List; import java.util.concurrent.CountDownLatch; +import com.redhat.thermostat.common.portability.PortableProcessFactory; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -271,14 +272,16 @@ }; // in Windows we need to ensure the drive letter appears - by calling getAbsolutePath() - String[] winArgs = new String[] { + // avoid this call in non-windows to simplify test setup + String[] winArgs = OS.IS_WINDOWS ? new String[] { "cmd", "/c", new File("/path/to/thermostat/home/thermostat-command-channel.cmd").getAbsolutePath(), "127.0.0.1", "123", - new File("/path/to/ipc/config").getAbsolutePath() - }; + new File("/path/to/ipc/config").getAbsolutePath(), + Integer.toString(PortableProcessFactory.getInstance().getCurrentProcessPid()) + } : null; final String[] expectedArgs = OS.IS_UNIX ? linuxArgs : winArgs;
--- a/common/portability/Makefile Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/Makefile Tue May 30 16:30:17 2017 -0400 @@ -30,9 +30,9 @@ INCLUDE = -I $(TARGET_DIR) -I "$(JAVA_HOME)/include/" -I "$(JAVA_HOME)/include/$(JNI_PLATFORM)" -HOSTNAME_SOURCES = src/main/native/HostName.c -HOSTNAME_TARGET = $(TARGET_DIR)/HostName.c -HOSTNAME_OBJECTS = $(HOSTNAME_TARGET:.c=.o) +POSIX_HELPER_SOURCES = src/main/native/PosixHelperImpl.c +POSIX_HELPER_TARGET = $(TARGET_DIR)/PosixHelperImpl.c +POSIX_HELPER_OBJECTS = $(POSIX_HELPER_TARGET:.c=.o) USERNAME_SOURCES = src/main/native/UserNameUtilImpl.c USERNAME_TARGET = $(TARGET_DIR)/UserNameUtilImpl.c @@ -53,7 +53,7 @@ EXECUTABLES = $(EXECUTABLE) .PHONY:UserNameUtilImpl -JNI_LIST = com.redhat.thermostat.common.portability.HostName com.redhat.thermostat.common.portability.internal.linux.UserNameUtilImpl +JNI_LIST = com.redhat.thermostat.common.portability.internal.PosixHelperImpl com.redhat.thermostat.common.portability.internal.linux.UserNameUtilImpl ifeq ($(JNI_PLATFORM),win32) JNI_LIST += com.redhat.thermostat.common.portability.internal.windows.WindowsHelperImpl @@ -67,19 +67,18 @@ $(JNI_LIST): $(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST) -all: $(JNI_LIST) init $(HOSTNAME_SOURCES) $(USERNAME_SOURCES) $(HELPER_SOURCES) $(EXECUTABLES) +all: $(JNI_LIST) init $(POSIX_HELPER_SOURCES) $(USERNAME_SOURCES) $(HELPER_SOURCES) $(EXECUTABLES) .PHONY: init: - $(COPY) $(HOSTNAME_SOURCES) $(HOSTNAME_TARGET) + $(COPY) $(POSIX_HELPER_SOURCES) $(POSIX_HELPER_TARGET) $(COPY) $(USERNAME_SOURCES) $(USERNAME_TARGET) ifneq ($(strip $(HELPER_SOURCES)),) $(COPY) $(HELPER_SOURCES) $(HELPER_TARGET) endif -$(EXECUTABLE): $(HOSTNAME_OBJECTS) $(USERNAME_OBJECTS) $(HELPER_OBJECTS) - $(CC) $(MYLDFLAGS) $(LDFLAGS) $(HOSTNAME_OBJECTS) $(USERNAME_OBJECTS) $(HELPER_OBJECTS) $(PLATFORM_LIBS) $(HELPER_LIBS) -o $(TARGET_DIR)/$@ - +$(EXECUTABLE): $(POSIX_HELPER_OBJECTS) $(USERNAME_OBJECTS) $(HELPER_OBJECTS) + $(CC) $(MYLDFLAGS) $(LDFLAGS) $(POSIX_HELPER_OBJECTS) $(USERNAME_OBJECTS) $(HELPER_OBJECTS) $(PLATFORM_LIBS) $(HELPER_LIBS) -o $(TARGET_DIR)/$@ .c.o: $(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@ @@ -91,7 +90,7 @@ rm -f $(TARGET_DIR)/$(EXECUTABLE) clean-obj: - rm -f $(HOSTNAME_OBJECTS) + rm -f $(POSIX_HELPER_OBJECTS) rm -f $(USERNAME_OBJECTS) rm -f $(HELPER_OBJECTS)
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/HostName.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/HostName.java Tue May 30 16:30:17 2017 -0400 @@ -37,16 +37,17 @@ package com.redhat.thermostat.common.portability; import com.redhat.thermostat.common.portability.internal.PortableNativeLibraryLoader; +import com.redhat.thermostat.common.portability.internal.PosixHelperImpl; /** * Finds the current host name without doing a DNS lookup */ public class HostName extends PortableNativeLibraryLoader { + private static PosixHelperImpl helper = new PosixHelperImpl(); + public static String getLocalHostName() { - return getHostName(); + return helper.getLocalHostName(); } - - private static native String getHostName(); }
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/PortableHost.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/PortableHost.java Tue May 30 16:30:17 2017 -0400 @@ -54,7 +54,7 @@ PortableMemoryStat getMemoryStat(); - // size of array containing CPU statistics for idle, system and user times + // represents size of array with idle, system and user ticks or percentages int CPU_TIMES_SIZE = 3; // returns an array (one row per CPU) of an array of ints (idle, system and user ticks)
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/PortableProcess.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/PortableProcess.java Tue May 30 16:30:17 2017 -0400 @@ -59,4 +59,6 @@ boolean terminateProcess(int pid, boolean wait); boolean terminateProcess(int pid, int exitcode, int waitMillis); + + int getCurrentProcessPid(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/ProcessWaiterMain.java Tue May 30 16:30:17 2017 -0400 @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.common.portability; + +public class ProcessWaiterMain { + + private static final boolean verbose = false; + private static final int TICKTIME = 1000; + + public static void main(String args[]) { + for (String pidStr : args) { + final int pid = Integer.parseInt(pidStr); + if (pid != 0) { + ProcessWatcher watcher = new ProcessWatcher(pid, TICKTIME) { + @Override + public void onProcessExit() { + if (verbose) { + System.err.println("process " + pid + " no longer exists"); + } + } + }; + watcher.start(); + try { + watcher.join(); + } catch (InterruptedException ignored) { + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/ProcessWatcher.java Tue May 30 16:30:17 2017 -0400 @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.common.portability; + +public abstract class ProcessWatcher extends Thread { + + private final int pidToWatch; + private final long sleepTimeMs; + private PortableProcess processChecker = PortableProcessFactory.getInstance(); + + protected ProcessWatcher(int pid, long sleepTimeMs) { + this.pidToWatch = pid; + this.sleepTimeMs = sleepTimeMs; + setName("process watcher"); + setDaemon(true); + } + + public void run() { + boolean parentIsRunning = true; + while (parentIsRunning) { + parentIsRunning = processChecker.exists(pidToWatch); + if (parentIsRunning) { + tick(); + try { + Thread.sleep(sleepTimeMs); + } catch (InterruptedException ignored) { + } + } + } + onProcessExit(); + } + + public void tick() {} + + abstract public void onProcessExit(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/PosixHelperImpl.java Tue May 30 16:30:17 2017 -0400 @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.common.portability.internal; + +public class PosixHelperImpl { + + public int getCurrentProcessPid() { + return getCurrentProcessID0(); + } + + public String getLocalHostName() { + return getHostName0(); + } + + private static native int getCurrentProcessID0(); + private static native String getHostName0(); +}
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableHostImpl.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableHostImpl.java Tue May 30 16:30:17 2017 -0400 @@ -45,9 +45,9 @@ import com.redhat.thermostat.common.Size; import com.redhat.thermostat.common.Size.Unit; -import com.redhat.thermostat.common.portability.HostName; import com.redhat.thermostat.common.portability.PortableHost; import com.redhat.thermostat.common.portability.PortableMemoryStat; +import com.redhat.thermostat.common.portability.internal.PosixHelperImpl; import com.redhat.thermostat.common.portability.internal.UnimplementedError; import com.redhat.thermostat.common.portability.linux.ProcDataSource; import com.redhat.thermostat.common.utils.LoggingUtils; @@ -86,7 +86,6 @@ } } - LinuxPortableHostImpl(ProcDataSource dataSource) { this.dataSource = dataSource; } @@ -145,7 +144,7 @@ // if fails, try to get hostname without dns lookup if (hostname == null) { - hostname = HostName.getLocalHostName(); + hostname = new PosixHelperImpl().getLocalHostName(); } // still null, use localhost
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableProcessImpl.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/linux/LinuxPortableProcessImpl.java Tue May 30 16:30:17 2017 -0400 @@ -42,6 +42,7 @@ import com.redhat.thermostat.common.portability.PortableProcessStat; import com.redhat.thermostat.common.portability.PortableVmIoStat; import com.redhat.thermostat.common.portability.ProcessChecker; +import com.redhat.thermostat.common.portability.internal.PosixHelperImpl; import com.redhat.thermostat.common.portability.internal.UnimplementedError; import com.redhat.thermostat.common.portability.internal.linux.vmio.LinuxVmIoStatBuilderImpl; import com.redhat.thermostat.common.portability.internal.linux.vmio.ProcIoDataReader; @@ -54,6 +55,7 @@ private LinuxPortableProcessStatBuilderImpl procStatHelper; private LinuxProcessEnvironmentBuilderImpl procEnvHelper; private LinuxVmIoStatBuilderImpl vmioHelper; + private PosixHelperImpl posixHelper; public static LinuxPortableProcessImpl INSTANCE = new LinuxPortableProcessImpl(new SystemClock(), new ProcDataSource()); @@ -65,6 +67,7 @@ procStatHelper = new LinuxPortableProcessStatBuilderImpl(dataSource); procEnvHelper = new LinuxProcessEnvironmentBuilderImpl(dataSource); vmioHelper = new LinuxVmIoStatBuilderImpl(clock, new ProcIoDataReader(dataSource)); + posixHelper = new PosixHelperImpl(); } @Override @@ -111,4 +114,9 @@ public boolean terminateProcess(int pid, int exitcode, int waitMillis) { throw new UnimplementedError("terminateProcess()"); } + + @Override + public int getCurrentProcessPid() { + return posixHelper.getCurrentProcessPid(); + } }
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/macos/MacOSProcessImpl.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/macos/MacOSProcessImpl.java Tue May 30 16:30:17 2017 -0400 @@ -40,6 +40,7 @@ import com.redhat.thermostat.common.portability.PortableProcess; import com.redhat.thermostat.common.portability.PortableProcessStat; import com.redhat.thermostat.common.portability.PortableVmIoStat; +import com.redhat.thermostat.common.portability.internal.PosixHelperImpl; import java.util.Map; @@ -47,6 +48,7 @@ public static final MacOSProcessImpl INSTANCE = new MacOSProcessImpl(); private static final MacOSHelperImpl helper = MacOSHelperImpl.INSTANCE; + private PosixHelperImpl posixHelper = new PosixHelperImpl(); @Override public boolean exists(int pid) { @@ -95,4 +97,9 @@ public boolean terminateProcess(int pid, int exitcode, int waitMillis) { return helper.terminateProcess(pid, exitcode, waitMillis); } + + @Override + public int getCurrentProcessPid() { + return posixHelper.getCurrentProcessPid(); + } }
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsHelperImpl.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsHelperImpl.java Tue May 30 16:30:17 2017 -0400 @@ -45,6 +45,7 @@ import java.util.HashMap; import java.util.Map; + /** * Utility class to access Windows native code */ @@ -146,11 +147,7 @@ } public boolean exists(int pid) { - final long hnd = getLimitedProcessHandle0(pid); - if (hnd != 0) { - closeHandle0(hnd); - } - return hnd != 0; + return exists0(pid) != 0; } public String getUserName(int pid) { @@ -327,6 +324,7 @@ private static native Object getEnvironment0(long hProcess, int mode); // mode = 0 returns DirectByteBuffer, 1 = String cwd, 2 = String execuatable, 3 = String command line private static native boolean getProcessInfo0(int pid, long[] info); private static native boolean getProcessIOInfo0(int pid, long[] info); + private static native int exists0(int pid); private static native int getCurrentProcessID0(); private static native long getCurrentProcessHandle0();
--- a/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsPortableProcessImpl.java Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsPortableProcessImpl.java Tue May 30 16:30:17 2017 -0400 @@ -101,4 +101,9 @@ public boolean terminateProcess(int pid, int exitcode, int waitMillis) { return helper.terminateProcess(pid, exitcode, waitMillis); } + + @Override + public int getCurrentProcessPid() { + return helper.getCurrentProcessPid(); + } }
--- a/common/portability/src/main/native/HostName.c Thu May 25 13:40:02 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -#include "com_redhat_thermostat_common_portability_HostName.h" - -#include <jni.h> -#include <unistd.h> -#include <string.h> - -#if !defined(_WIN32) -# include <netdb.h> -#else // windows -# include <winsock2.h> -#endif - -#ifndef NI_MAXHOST -#define NI_MAXHOST 1025 -#endif /* NI_MAXHOST */ - -JNIEXPORT jstring JNICALL -Java_com_redhat_thermostat_common_portability_HostName_getHostName - (JNIEnv *env, jclass HostNameClass) -{ - char hostname[NI_MAXHOST]; - memset(hostname, 0, sizeof(hostname)); - - if (gethostname(hostname, sizeof(hostname)) == 0) { - return (*env)->NewStringUTF(env, hostname); - } - return NULL; -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/portability/src/main/native/PosixHelperImpl.c Tue May 30 16:30:17 2017 -0400 @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +#include "com_redhat_thermostat_common_portability_internal_PosixHelperImpl.h" + +#include <jni.h> +#include <unistd.h> +#include <string.h> + +#if !defined(_WIN32) +# include <netdb.h> +#else // windows +# include <winsock2.h> +#endif + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif /* NI_MAXHOST */ + +JNIEXPORT jstring JNICALL +Java_com_redhat_thermostat_common_portability_internal_PosixHelperImpl_getHostName0 + (JNIEnv *env, jclass HostNameClass) +{ + char hostname[NI_MAXHOST]; + memset(hostname, 0, sizeof(hostname)); + + if (gethostname(hostname, sizeof(hostname)) == 0) { + return (*env)->NewStringUTF(env, hostname); + } + return NULL; +} + + +JNIEXPORT jint JNICALL +Java_com_redhat_thermostat_common_portability_internal_PosixHelperImpl_getCurrentProcessID0 + (JNIEnv *env, jclass posixHelperClass) +{ + return (jint)getpid(); +}
--- a/common/portability/src/main/native/WindowsHelperImpl.c Thu May 25 13:40:02 2017 -0400 +++ b/common/portability/src/main/native/WindowsHelperImpl.c Tue May 30 16:30:17 2017 -0400 @@ -497,11 +497,23 @@ */ JNIEXPORT jobject JNICALL Java_com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl_getEnvironment0 - (JNIEnv *env, jclass winHelperClass, jlong hProcess, jint callmode) { + (JNIEnv *env, jclass winHelperClass, jlong lhProcess, jint callmode) { + + HANDLE hProcess = (HANDLE)(lhProcess); + + BOOL isWowProcess = FALSE; + IsWow64Process(hProcess, &isWowProcess); + if (isWowProcess) { +#if defined(DEBUG_GETENV) + fprintf(stderr, "process pid=%I64d hnd=%ld is 32-bit; getEnvironment() is unsupported\n", (long long)hProcess, (long)GetProcessId(hProcess)); +#endif + return NULL; + } + PROCESS_BASIC_INFORMATION procBasicInfo = { 0 }; ULONG uReturnLength = 0; - NTSTATUS ntStat = QueryInformationProcesss((HANDLE)hProcess, + NTSTATUS ntStat = QueryInformationProcesss(hProcess, ProcessBasicInformation, &procBasicInfo, sizeof(procBasicInfo), @@ -526,8 +538,8 @@ #endif //DEBUG_GETENV // read the PEB from the other process (which is assumed to be 64-bit) - if (!ReadProcessMemory((HANDLE)hProcess,(LPCVOID)procBasicInfo.PebBaseAddress, &procEnvBlock, sizeof(procEnvBlock), &returnByteCount)) { - fprintf(stderr, "Error Reading Process Memory err=%ld", GetLastError()); + if (!ReadProcessMemory(hProcess,(LPCVOID)procBasicInfo.PebBaseAddress, &procEnvBlock, sizeof(procEnvBlock), &returnByteCount)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d, err=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError()); return NULL; } @@ -548,8 +560,8 @@ fprintf(stderr, "testing RTL_USER_PROCESS_PARAMETERS memory at 0x%ld\n", (long)pRTLUserInfo); #endif //DEBUG_GETENV - if (!checkReadAccess((HANDLE)hProcess, pRTLUserInfo, &readableSize)) { - fprintf(stderr, "Error Reading Process Memory err=%ld", GetLastError()); + if (!checkReadAccess(hProcess, pRTLUserInfo, &readableSize)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError()); return NULL; } @@ -560,8 +572,8 @@ // Get the first 0x64 bytes of RTL_USER_PROCESS_PARAMETERS strcuture RTL_USER_PROCESS_PARAMETERS64 upp = {0}; - if (!ReadProcessMemory((HANDLE)hProcess, (LPCVOID)pRTLUserInfo, &upp, sizeof(RTL_USER_PROCESS_PARAMETERS64), &returnByteCount)) { - fprintf(stderr, "Error Reading Process Memory err=%ld", GetLastError()); + if (!ReadProcessMemory(hProcess, (LPCVOID)pRTLUserInfo, &upp, sizeof(RTL_USER_PROCESS_PARAMETERS64), &returnByteCount)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError()); return NULL; } @@ -582,8 +594,8 @@ fprintf(stderr, "reading CurrentWorkingDirectory string at 0x%lx length %ld\n", (long)upp.CurrentWorkingDirectory.Buffer, (long)upp.CurrentWorkingDirectory.Length); #endif //DEBUG_GETENV WCHAR* sb = malloc(upp.CurrentWorkingDirectory.Length); - if (!ReadProcessMemory((HANDLE)hProcess, (LPCVOID)upp.CurrentWorkingDirectory.Buffer, sb, upp.CurrentWorkingDirectory.Length, &returnByteCount)) { - fprintf(stderr, "Error Reading Process Memory err=%ld bytes=%ld\n", GetLastError(), (long)returnByteCount); + if (!ReadProcessMemory(hProcess, (LPCVOID)upp.CurrentWorkingDirectory.Buffer, sb, upp.CurrentWorkingDirectory.Length, &returnByteCount)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld bytes=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError(), (long)returnByteCount); free(sb); return NULL; } @@ -598,8 +610,8 @@ fprintf(stderr, "reading string at 0x%lx length %ld\n", (long)upp.ImagePathName.Buffer, (long)upp.ImagePathName.Length); #endif //DEBUG_GETENV WCHAR* sb = malloc(upp.ImagePathName.Length); - if (!ReadProcessMemory((HANDLE)hProcess, (LPCVOID)upp.ImagePathName.Buffer, sb, upp.ImagePathName.Length, &returnByteCount)) { - fprintf(stderr, "Error Reading Process Memory err=%ld bytes=%ld\n", GetLastError(), (long)returnByteCount); + if (!ReadProcessMemory(hProcess, (LPCVOID)upp.ImagePathName.Buffer, sb, upp.ImagePathName.Length, &returnByteCount)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld bytes=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError(), (long)returnByteCount); free(sb); return NULL; } @@ -614,8 +626,8 @@ fprintf(stderr, "reading string at 0x%lx length %ld\n", (long)upp.CommandLine.Buffer, (long)upp.CommandLine.Length); #endif //DEBUG_GETENV WCHAR* sb = malloc(upp.CommandLine.Length); - if (!ReadProcessMemory((HANDLE)hProcess, (LPCVOID)upp.CommandLine.Buffer, sb, upp.CommandLine.Length, &returnByteCount)) { - fprintf(stderr, "Error Reading Process Memory err=%ld bytes=%ld\n", GetLastError(), (long)returnByteCount); + if (!ReadProcessMemory(hProcess, (LPCVOID)upp.CommandLine.Buffer, sb, upp.CommandLine.Length, &returnByteCount)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld bytes=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError(), (long)returnByteCount); free(sb); return NULL; } @@ -630,8 +642,8 @@ // find out how much we can read, and then read it // this will read more than just the environment, but there's not a lot we can do cleanly - if (!checkReadAccess((HANDLE)hProcess, strPtr, &readableSize)) { - fprintf(stderr, "Error Reading Process Memory err=%ld siz=0x%lx", GetLastError(), (long)readableSize); + if (!checkReadAccess(hProcess, strPtr, &readableSize)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld siz=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError(), (long)readableSize); return NULL; } // constrain readableSize to some maximum @@ -644,8 +656,8 @@ fprintf(stderr, "reading string at 0x%lx length %ld\n", (long)strPtr, (long)readableSize); #endif //DEBUG_GETENV WCHAR* sb = malloc(readableSize); - if (!ReadProcessMemory((HANDLE)hProcess, (LPCVOID)strPtr, sb, readableSize, &returnByteCount)) { - fprintf(stderr, "Error Reading Process Memory err=%ld bytes=%ld\n", GetLastError(), (long)returnByteCount); + if (!ReadProcessMemory(hProcess, (LPCVOID)strPtr, sb, readableSize, &returnByteCount)) { + fprintf(stderr, "Error reading process memory hnd=%I64d pid=%ld line=%d err=%ld readable=%ld retbytes=%ld\n", (long long)hProcess, (long)GetProcessId(hProcess), __LINE__, GetLastError(), (long)readableSize, (long)returnByteCount); free(sb); return NULL; } @@ -930,6 +942,30 @@ /* * Class: com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl + * Method: exists0 + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl_exists0 + (JNIEnv *env, jclass winHelperClass, jint pid) { + + if (pid == 0) + return 1; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (hProcess == 0) + return 0; + LPDWORD ret = 0; + int rc = GetExitCodeProcess(hProcess, &ret); + CloseHandle(hProcess); + if (rc) { + return ret == STILL_ACTIVE; + } + else { + return 0; + } +} + +/* + * Class: com_redhat_thermostat_common_portability_internal_windows_WindowsHelperImpl * Method: closeHandle0 * Signature: (J)V */
--- a/distribution/packaging/fedora/thermostat.spec Thu May 25 13:40:02 2017 -0400 +++ b/distribution/packaging/fedora/thermostat.spec Tue May 30 16:30:17 2017 -0400 @@ -673,6 +673,7 @@ src/main/java/com/redhat/thermostat/common/portability/HostName.java \ src/main/java/com/redhat/thermostat/common/portability/UserNameUtil.java \ src/main/java/com/redhat/thermostat/common/portability/UserNameLookupException.java \ + src/main/java/com/redhat/thermostat/common/portability/internal/PosixHelperImpl.java \ src/main/java/com/redhat/thermostat/common/portability/internal/PortableNativeLibraryLoader.java \ src/main/java/com/redhat/thermostat/common/portability/internal/linux/UserNameUtilImpl.java \ src/main/java/com/redhat/thermostat/common/portability/internal/windows/WindowsHelperImpl.java
--- a/distribution/scripts/thermostat-command-channel Thu May 25 13:40:02 2017 -0400 +++ b/distribution/scripts/thermostat-command-channel Tue May 30 16:30:17 2017 -0400 @@ -61,6 +61,7 @@ IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-shared-config-@project.version@.jar" IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-agent-command-@project.version@.jar" IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-common-command-@project.version@.jar" +IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-common-portability-@project.version@.jar" IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-agent-command-server-@project.version@.jar" IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/netty-buffer-@netty.version@.jar" IPC_CLASSPATH="${IPC_CLASSPATH}:${THERMOSTAT_LIBS}/netty-common-@netty.version@.jar"
--- a/distribution/windows/scripts/thermostat-command-channel.cmd Thu May 25 13:40:02 2017 -0400 +++ b/distribution/windows/scripts/thermostat-command-channel.cmd Tue May 30 16:30:17 2017 -0400 @@ -36,13 +36,13 @@ setlocal -if "%3"=="" goto usage -if not "%4"=="" goto usage +if "%4"=="" goto usage +if not "%5"=="" goto usage goto skipfuncdefs :usage - echo "usage: %~f0 <hostname> <port> <ipcConfigFile>" + echo "usage: %~f0 <hostname> <port> <ipcConfigFile> [<parentPid>]" exit /b 1 :skipfuncdefs @@ -50,6 +50,7 @@ set HOSTNAME=%1 set PORT=%2 set CONFIG_FILE=%3 +set PARENT_PID=%4 :: Source thermostat-ipc-client-common from same directory as this script :: Defines IPC_CLASSPATH variable with JARs necessary for the IPC service @@ -68,6 +69,7 @@ set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\thermostat-shared-config-@project.version@.jar set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\thermostat-agent-command-@project.version@.jar set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\thermostat-common-command-@project.version@.jar +set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\thermostat-common-portability-@project.version@.jar set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\thermostat-agent-command-server-@project.version@.jar set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\netty-buffer-@netty.version@.jar set IPC_CLASSPATH=%IPC_CLASSPATH%;%THERMOSTAT_LIBS%\netty-common-@netty.version@.jar @@ -87,7 +89,7 @@ :: Start server set CONFIG_FILE_ARG=-DipcConfigFile=%CONFIG_FILE% -%JAVA% %CONFIG_FILE_ARG% %LOGGING_ARGS% -cp %IPC_CLASSPATH% %DEBUG_OPTS% %CMD_CHANNEL_CLASS% %HOSTNAME% %PORT% +%JAVA% %CONFIG_FILE_ARG% %LOGGING_ARGS% -cp %IPC_CLASSPATH% %DEBUG_OPTS% %CMD_CHANNEL_CLASS% %HOSTNAME% %PORT% %PARENT_PID%