Recover Android VPN probes after first stall

This commit is contained in:
2026-05-15 07:58:36 +03:00
parent d2746cac68
commit 620d5a97c9
2 changed files with 49 additions and 11 deletions
+2 -2
View File
@@ -30,8 +30,8 @@ android {
applicationId "su.cin.rapvpn" applicationId "su.cin.rapvpn"
minSdk 26 minSdk 26
targetSdk 35 targetSdk 35
versionCode 185 versionCode 186
versionName "0.2.185" versionName "0.2.186"
buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\"" buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\""
buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\"" buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\""
buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\"" buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\""
@@ -69,6 +69,10 @@ public class RapDiagnosticService extends Service {
private static final long COMMAND_STALE_MS = 45000; private static final long COMMAND_STALE_MS = 45000;
private static final long COMMAND_ORPHAN_MS = 60000; private static final long COMMAND_ORPHAN_MS = 60000;
private static final long POLL_FORCE_MS = 45000; private static final long POLL_FORCE_MS = 45000;
private static final int RECOVERY_TCP_TIMEOUT_MS = 8000;
private static final int RECOVERY_PAGE_TIMEOUT_MS = 25000;
private static final int RECOVERY_DOWNLOAD_CONNECT_TIMEOUT_MS = 8000;
private static final int RECOVERY_DOWNLOAD_READ_TIMEOUT_MS = 12000;
private volatile boolean running; private volatile boolean running;
private Thread worker; private Thread worker;
private Thread supervisor; private Thread supervisor;
@@ -478,14 +482,14 @@ public class RapDiagnosticService extends Service {
} }
if (isRecoverableVPNProbe(type) && looksLikeVPNStall(result)) { if (isRecoverableVPNProbe(type) && looksLikeVPNStall(result)) {
String firstResult = result; String firstResult = result;
Thread.sleep(1500); String recovery = controlledRestartVPNRuntime(client, clusterId);
String fastRetry = runVPNProbeCommand(type, params); Thread.sleep(2500);
if (!looksLikeVPNStall(fastRetry)) { String recoveryRetry = runVPNProbeCommand(type, recoveryProbePayload(type, params), true);
result = firstResult + " | fast_retry=" + fastRetry; if (!looksLikeVPNStall(recoveryRetry)) {
result = firstResult + " | recovery=" + recovery + " | recovery_retry=" + recoveryRetry;
} else { } else {
String recovery = controlledRestartVPNRuntime(client, clusterId); Thread.sleep(1500);
Thread.sleep(4000); result = firstResult + " | recovery=" + recovery + " | recovery_retry=" + recoveryRetry + " | final_retry=" + runVPNProbeCommand(type, recoveryProbePayload(type, params), true);
result = firstResult + " | fast_retry=" + fastRetry + " | recovery=" + recovery + " | retry=" + runVPNProbeCommand(type, params);
} }
} }
lastCommandType = type; lastCommandType = type;
@@ -661,6 +665,10 @@ public class RapDiagnosticService extends Service {
} }
private String runVPNProbeCommand(String type, JSONObject payload) { private String runVPNProbeCommand(String type, JSONObject payload) {
return runVPNProbeCommand(type, payload, false);
}
private String runVPNProbeCommand(String type, JSONObject payload, boolean recoveryAttempt) {
if ("vpn_http_get".equals(type)) { if ("vpn_http_get".equals(type)) {
return runVPNHttpGet(payload.optString("url", "http://192.168.200.61:18080/")); return runVPNHttpGet(payload.optString("url", "http://192.168.200.61:18080/"));
} }
@@ -671,11 +679,37 @@ public class RapDiagnosticService extends Service {
return runVPNTCPConnect(payload.optString("host", "192.168.200.95"), payload.optInt("port", 3389), payload.optInt("timeout_ms", 7000)); return runVPNTCPConnect(payload.optString("host", "192.168.200.95"), payload.optInt("port", 3389), payload.optInt("timeout_ms", 7000));
} }
if ("vpn_download_test".equals(type)) { if ("vpn_download_test".equals(type)) {
if (recoveryAttempt) {
return runVPNDownloadTest(
payload.optString("url", "http://192.168.200.61:18080/downloads/rap-android-rdp-vpn-build.json"),
RECOVERY_DOWNLOAD_CONNECT_TIMEOUT_MS,
RECOVERY_DOWNLOAD_READ_TIMEOUT_MS);
}
return runVPNDownloadTest(payload.optString("url", "http://192.168.200.61:18080/downloads/rap-android-rdp-vpn-build.json")); return runVPNDownloadTest(payload.optString("url", "http://192.168.200.61:18080/downloads/rap-android-rdp-vpn-build.json"));
} }
return "retry skipped: unsupported probe " + type; return "retry skipped: unsupported probe " + type;
} }
private JSONObject recoveryProbePayload(String type, JSONObject payload) {
JSONObject copy;
try {
copy = payload == null ? new JSONObject() : new JSONObject(payload.toString());
} catch (Exception e) {
copy = new JSONObject();
}
try {
if ("vpn_tcp_connect".equals(type) || "vpn_rdp_probe".equals(type)) {
int requested = copy.optInt("timeout_ms", RECOVERY_TCP_TIMEOUT_MS);
copy.put("timeout_ms", Math.max(1000, Math.min(requested, RECOVERY_TCP_TIMEOUT_MS)));
} else if ("vpn_page_probe".equals(type)) {
int requested = copy.optInt("timeout_ms", RECOVERY_PAGE_TIMEOUT_MS);
copy.put("timeout_ms", Math.max(10000, Math.min(requested, RECOVERY_PAGE_TIMEOUT_MS)));
}
} catch (Exception ignored) {
}
return copy;
}
private String controlledRestartVPNRuntime(RapApiClient client, String clusterId) { private String controlledRestartVPNRuntime(RapApiClient client, String clusterId) {
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
String connectionId = prefs.getString(PREF_VPN_CONNECTION_ID, ""); String connectionId = prefs.getString(PREF_VPN_CONNECTION_ID, "");
@@ -1051,6 +1085,10 @@ public class RapDiagnosticService extends Service {
} }
private String runVPNDownloadTest(String target) { private String runVPNDownloadTest(String target) {
return runVPNDownloadTest(target, 15000, 20000);
}
private String runVPNDownloadTest(String target, int connectTimeoutMs, int readTimeoutMs) {
try { try {
Network vpn = waitForVPNNetwork(5000); Network vpn = waitForVPNNetwork(5000);
if (vpn == null) { if (vpn == null) {
@@ -1058,8 +1096,8 @@ public class RapDiagnosticService extends Service {
} }
URL url = new URL(target); URL url = new URL(target);
HttpURLConnection connection = (HttpURLConnection) vpn.openConnection(url); HttpURLConnection connection = (HttpURLConnection) vpn.openConnection(url);
connection.setConnectTimeout(15000); connection.setConnectTimeout(Math.max(1000, connectTimeoutMs));
connection.setReadTimeout(20000); connection.setReadTimeout(Math.max(1000, readTimeoutMs));
connection.setInstanceFollowRedirects(false); connection.setInstanceFollowRedirects(false);
int code = connection.getResponseCode(); int code = connection.getResponseCode();
int bytes = 0; int bytes = 0;