2022-09-18 16:44:58 -04:00
|
|
|
package net.i2p.router;
|
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStreamReader;
|
2022-09-19 03:10:47 -04:00
|
|
|
import javax.swing.JOptionPane;
|
2022-09-18 16:44:58 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Provides querying of Windows services in order to discover I2P Routers
|
|
|
|
* running as a service and avoid launching jpackaged routers redundantly.
|
|
|
|
* It will prompt a user to start their I2P service if one is discovered.
|
2022-09-18 17:20:00 -04:00
|
|
|
*
|
2022-09-18 16:44:58 -04:00
|
|
|
* see also:
|
|
|
|
* https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/sc-query
|
|
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicecontrollerstatus?view=dotnet-plat-ext-6.0
|
2022-09-18 17:20:00 -04:00
|
|
|
* https://stackoverflow.com/questions/10604844/how-to-verify-whether-service-exists-in-services-msc
|
|
|
|
* C#, API ideas only
|
2022-09-18 16:44:58 -04:00
|
|
|
* https://stackoverflow.com/questions/334471/need-a-way-to-check-status-of-windows-service-programmatically
|
|
|
|
* https://stackoverflow.com/questions/5388888/find-status-of-windows-service-from-java-application
|
|
|
|
* https://stackoverflow.com/questions/21566847/how-to-check-particular-windows-service-is-running-using
|
|
|
|
* https://stackoverflow.com/questions/9792051/start-windows-service-with-java
|
2022-09-18 17:20:00 -04:00
|
|
|
*
|
2022-09-18 16:44:58 -04:00
|
|
|
* There's a chance we can't tell ServiceController to do anything so if
|
|
|
|
* that is the case then we'll just launch services.msc and tell the user to
|
|
|
|
* take it from there.
|
|
|
|
*
|
|
|
|
* @author idk
|
|
|
|
* @since 1.9.7
|
|
|
|
*/
|
|
|
|
|
|
|
|
public class WindowsServiceUtil {
|
|
|
|
public WindowsServiceUtil() {}
|
2022-09-19 00:26:52 -04:00
|
|
|
public static String queryService(String serviceName) {
|
2022-09-18 16:44:58 -04:00
|
|
|
String result = "";
|
|
|
|
String line;
|
|
|
|
ProcessBuilder pb = new ProcessBuilder("sc", "query", serviceName);
|
|
|
|
try {
|
|
|
|
Process p = pb.start();
|
|
|
|
try {
|
|
|
|
p.waitFor(); // wait for process to finish then continue.
|
|
|
|
BufferedReader bri =
|
|
|
|
new BufferedReader(new InputStreamReader(p.getInputStream()));
|
|
|
|
while ((line = bri.readLine()) != null) {
|
|
|
|
result += line;
|
|
|
|
}
|
|
|
|
} catch (InterruptedException e) {
|
2022-09-19 00:26:52 -04:00
|
|
|
System.err.println(e.toString());
|
2022-09-18 16:44:58 -04:00
|
|
|
} catch (IOException e) {
|
2022-09-19 00:26:52 -04:00
|
|
|
System.err.println(e.toString());
|
2022-09-18 16:44:58 -04:00
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
2022-09-19 00:26:52 -04:00
|
|
|
System.err.println(e.toString());
|
2022-09-18 16:44:58 -04:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2022-09-19 00:26:52 -04:00
|
|
|
public static String getStatePrefix(String qResult) {
|
2022-09-18 17:20:00 -04:00
|
|
|
String statePrefix = "STATE : ";
|
|
|
|
// get the first occurrence of "STATE", then find the
|
|
|
|
// next occurrence of of ":" after that. Count the
|
|
|
|
// spaces between.
|
|
|
|
int indexOfState = qResult.indexOf("STATE");
|
|
|
|
if (indexOfState >= 0) {
|
|
|
|
int indexOfColon = qResult.indexOf(":", indexOfState);
|
|
|
|
statePrefix = "STATE";
|
2022-09-19 02:40:52 -04:00
|
|
|
for (int f = indexOfState + 5; f < indexOfColon; f++) {
|
2022-09-18 17:20:00 -04:00
|
|
|
statePrefix += " ";
|
|
|
|
}
|
|
|
|
statePrefix += ": ";
|
|
|
|
}
|
|
|
|
return statePrefix;
|
|
|
|
}
|
2022-09-19 01:44:29 -04:00
|
|
|
public static int getServiceStateInt(String serviceName) {
|
2022-09-18 17:20:00 -04:00
|
|
|
// String statePrefix = "STATE : ";
|
|
|
|
String qResult = queryService(serviceName);
|
|
|
|
String statePrefix = getStatePrefix(qResult);
|
2022-09-18 16:44:58 -04:00
|
|
|
// check that the temp string contains the status prefix
|
2022-09-18 17:20:00 -04:00
|
|
|
int ix = qResult.indexOf(statePrefix);
|
2022-09-18 16:44:58 -04:00
|
|
|
if (ix >= 0) {
|
|
|
|
// compare status number to one of the states
|
2022-09-18 17:20:00 -04:00
|
|
|
String stateStr = qResult.substring(ix + statePrefix.length(),
|
|
|
|
ix + statePrefix.length() + 1);
|
2022-09-18 16:44:58 -04:00
|
|
|
int state = Integer.parseInt(stateStr);
|
2022-09-19 01:44:29 -04:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
return -2;
|
|
|
|
}
|
2022-09-19 02:40:52 -04:00
|
|
|
|
2022-09-19 03:10:47 -04:00
|
|
|
public static boolean isInstalled(String serviceName) {
|
|
|
|
if (getServiceState(serviceName).equals("uninstalled")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isStart(String serviceName) {
|
|
|
|
if (getServiceState(serviceName).equals("started")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (getServiceState(serviceName).equals("starting")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (getServiceState(serviceName).equals("resuming")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void promptServiceStartIfAvailable(String serviceName) {
|
|
|
|
if (isInstalled(serviceName)) {
|
|
|
|
if (!isStart(serviceName)) {
|
|
|
|
int a;
|
2022-09-19 12:34:41 -04:00
|
|
|
String message =
|
|
|
|
"It appears you have an existing I2P service installed.\n";
|
|
|
|
message +=
|
|
|
|
"However, it is not running yet. Would you like to start it?\n";
|
|
|
|
a = JOptionPane.showConfirmDialog(null, message,
|
|
|
|
"I2P Service detected not running",
|
|
|
|
JOptionPane.YES_NO_OPTION);
|
2022-09-19 03:10:47 -04:00
|
|
|
if (a == JOptionPane.NO_OPTION) {
|
2022-09-19 12:34:41 -04:00
|
|
|
// Do nothing here, this will continue on to launch a jpackaged router
|
2022-09-19 03:10:47 -04:00
|
|
|
} else {
|
2022-09-19 12:34:41 -04:00
|
|
|
// We can't just call `net start` or `sc start` directly, that throws
|
|
|
|
// a permission error. We can start services.msc though, where the
|
|
|
|
// user can start the service themselves. OR maybe we ask for
|
|
|
|
// elevation here? May need to refactor Elevator and Shell32X to
|
|
|
|
// achieve it though
|
2022-09-19 03:10:47 -04:00
|
|
|
}
|
2022-09-19 12:34:41 -04:00
|
|
|
} else {
|
|
|
|
// Here, the service is already started, so I2P should appear to be
|
|
|
|
// running to the other checks.
|
2022-09-19 03:10:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-19 01:44:29 -04:00
|
|
|
public static String getServiceState(String serviceName) {
|
|
|
|
String stateString = "uninstalled";
|
2022-09-19 02:40:52 -04:00
|
|
|
int state = getServiceStateInt(serviceName);
|
|
|
|
switch (state) {
|
|
|
|
case (1): // service stopped
|
|
|
|
stateString = "stopped";
|
|
|
|
break;
|
|
|
|
case (2): // service starting
|
|
|
|
stateString = "starting";
|
|
|
|
break;
|
|
|
|
case (3): // service stopping
|
|
|
|
stateString = "stopping";
|
|
|
|
break;
|
|
|
|
case (4): // service started
|
|
|
|
stateString = "started";
|
|
|
|
break;
|
|
|
|
case (5): // service resuming from pause
|
|
|
|
stateString = "resuming";
|
|
|
|
break;
|
|
|
|
case (6): // service pausing
|
|
|
|
stateString = "pausing";
|
|
|
|
break;
|
|
|
|
case (7): // service paused
|
|
|
|
stateString = "paused";
|
|
|
|
break;
|
|
|
|
}
|
2022-09-18 16:44:58 -04:00
|
|
|
return stateString;
|
|
|
|
}
|
2022-09-19 01:25:23 -04:00
|
|
|
public static void main(String args[]) {
|
2022-09-19 02:37:59 -04:00
|
|
|
// when querying the I2P router service installed by the IzPack installer
|
|
|
|
// this is the correct call.
|
2022-09-19 00:26:52 -04:00
|
|
|
String state = getServiceState("i2p");
|
2022-09-19 01:44:29 -04:00
|
|
|
int stateInt = getServiceStateInt("i2p");
|
2022-09-19 02:40:52 -04:00
|
|
|
System.out.println("i2p state: " + state + " code: " + stateInt);
|
2022-09-19 03:10:47 -04:00
|
|
|
promptServiceStartIfAvailable("i2p");
|
2022-09-19 00:26:52 -04:00
|
|
|
}
|
2022-09-18 16:44:58 -04:00
|
|
|
}
|