Files
i2p.firefox/java/net/i2p/router/WindowsServiceUtil.java

281 lines
9.5 KiB
Java

package net.i2p.router;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.swing.JOptionPane;
/*
* 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.
*
* 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
* https://stackoverflow.com/questions/10604844/how-to-verify-whether-service-exists-in-services-msc
* C#, API ideas only
* 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
*
* 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() {}
public String queryService(String serviceName) {
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) {
System.err.println(e.toString());
} catch (IOException e) {
System.err.println(e.toString());
}
} catch (IOException e) {
System.err.println(e.toString());
}
return result;
}
public String getStatePrefix(String qResult) {
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";
for (int f = indexOfState + 5; f < indexOfColon; f++) {
statePrefix += " ";
}
statePrefix += ": ";
}
return statePrefix;
}
public int getServiceStateInt(String serviceName) {
// String statePrefix = "STATE : ";
String qResult = queryService(serviceName);
String statePrefix = getStatePrefix(qResult);
// check that the temp string contains the status prefix
int ix = qResult.indexOf(statePrefix);
if (ix >= 0) {
// compare status number to one of the states
String stateStr = qResult.substring(ix + statePrefix.length(),
ix + statePrefix.length() + 1);
int state = Integer.parseInt(stateStr);
return state;
}
return -2;
}
public boolean isInstalled(String serviceName) {
if (getServiceState(serviceName).equals("uninstalled")) {
return false;
}
return true;
}
public 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 boolean promptServiceStartIfAvailable(String serviceName) {
if (osName() != "windows") {
return true;
}
if (isInstalled(serviceName)) {
if (!isStart(serviceName)) {
int a;
String message =
"It appears you have an existing I2P service installed.\n";
message +=
"However, it is not running yet. Please start it through `services.msc`.\n";
message +=
"If you click \"No\", the jpackage router will be launched instead.\n";
a = JOptionPane.showConfirmDialog(null, message,
"I2P Service detected not running",
JOptionPane.YES_NO_OPTION);
if (a == JOptionPane.NO_OPTION) {
// Do nothing here, this will continue on to launch a jpackaged router
return true;
} else {
// 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
ProcessBuilder pb =
new ProcessBuilder("C:\\Windows\\System32\\services.msc");
try {
Process p = pb.start();
int exitCode = p.waitFor();
if (exitCode != 0) {
return false;
}
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
return isStart("i2p");
}
return true;
}
return true;
}
public String ServiceUpdaterString() {
return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.su3";
}
public String ServiceBackupUpdaterString() {
return "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news.su3";
}
public String ServiceStaticUpdaterString() {
return "http://echelon.i2p/i2p/i2pupdate.sud,http://stats.i2p/i2p/i2pupdate.sud";
}
public String getProgramFilesInstall() {
String programFiles = System.getenv("PROGRAMFILES");
if (programFiles != null) {
File programFilesI2P = new File(programFiles, "i2p/i2p.exe");
if (programFilesI2P.exists())
return programFilesI2P.getAbsolutePath();
}
String programFiles86 = System.getenv("PROGRAMFILES86");
if (programFiles86 != null) {
File programFiles86I2P = new File(programFiles86, "i2p/i2p.exe");
if (programFiles86I2P.exists())
return programFiles86I2P.getAbsolutePath();
}
return null;
}
public boolean checkProgramFilesInstall() {
String programFiles = System.getenv("PROGRAMFILES");
if (programFiles != null) {
File programFilesI2P = new File(programFiles, "i2p/i2p.exe");
if (programFilesI2P.exists())
return true;
}
String programFiles86 = System.getenv("PROGRAMFILES86");
if (programFiles86 != null) {
File programFiles86I2P = new File(programFiles86, "i2p/i2p.exe");
if (programFiles86I2P.exists())
return true;
}
return false;
}
public boolean promptUserInstallStartIfAvailable() {
if (osName() != "windows") {
return true;
}
if (checkProgramFilesInstall()) {
int a;
String message =
"It appears you have an existing, unbundled I2P rotuer installed.\n";
message +=
"However, it is not running yet. Please start it using the shortcut on the desktop.\n";
message +=
"If you click \"No\", the Easy-Install router will be launched instead.\n";
a = JOptionPane.showConfirmDialog(null, message,
"I2P Service detected not running",
JOptionPane.YES_NO_OPTION);
if (a == JOptionPane.NO_OPTION) {
// Do nothing here, this will continue on to launch a jpackaged router
return true;
} else {
try {
String pfi = getProgramFilesInstall();
if (pfi != null)
Runtime.getRuntime().exec(new String[] {pfi});
} catch (IOException e) {
return false;
}
return true;
}
}
return true;
}
public String getServiceState(String serviceName) {
String stateString = "uninstalled";
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;
}
return stateString;
}
/**
* get the OS name(windows, mac, linux only)
*
* @return os name in lower-case, "windows" "mac" or "linux"
*/
protected String osName() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows"))
return "windows";
if (osName.contains("mac"))
return "mac";
return "linux";
}
public static void main(String args[]) {
WindowsServiceUtil wsu = new WindowsServiceUtil();
// when querying the I2P router service installed by the IzPack installer
// this is the correct call.
String state = wsu.getServiceState("i2p");
int stateInt = wsu.getServiceStateInt("i2p");
System.out.println("i2p state: " + state + " code: " + stateInt);
wsu.promptServiceStartIfAvailable("i2p");
}
}