diff --git a/jni/interface.c b/jni/interface.c index 0ae62f6..b8cdc5a 100644 --- a/jni/interface.c +++ b/jni/interface.c @@ -25,7 +25,6 @@ conf_path_file(const char *fn) static JNIEnv *env; static jclass cl_string; static jclass cl_simplesshdservice; -static jfieldID fid_sss_sshd_pid; extern int dropbear_main(int argc, char **argv); @@ -49,8 +48,6 @@ jni_init(JNIEnv *env_) CLASS(string, "java/lang/String") CLASS(simplesshdservice, "org/galexander/sshd/SimpleSSHDService") - STFIELD(sss_sshd_pid, simplesshdservice, "sshd_pid", "I") - return 1; } @@ -115,7 +112,7 @@ from_java_string(jobject s) return ret; } -JNIEXPORT void JNICALL +JNIEXPORT jint JNICALL Java_org_galexander_sshd_SimpleSSHDService_start_1sshd(JNIEnv *env_, jclass cl, jint port, jobject jpath, jobject jshell, jobject jhome, jobject jextra, @@ -167,23 +164,18 @@ Java_org_galexander_sshd_SimpleSSHDService_start_1sshd(JNIEnv *env_, (sizeof argv / sizeof *argv) - argc); fprintf(stderr, "starting dropbear\n"); retval = dropbear_main(argc, argv); + /* NB - probably not reachable */ fprintf(stderr, "dropbear finished (%d)\n", retval); - } else { - (*env)->SetStaticIntField(env, cl_simplesshdservice, - fid_sss_sshd_pid, pid); + exit(0); } + return pid; } JNIEXPORT void JNICALL -Java_org_galexander_sshd_SimpleSSHDService_stop_1sshd(JNIEnv *env_, jclass cl) +Java_org_galexander_sshd_SimpleSSHDService_kill(JNIEnv *env_, jclass cl, + jint pid) { - pid_t pid; - if (!jni_init(env_)) { - return; - } - pid = (*env)->GetStaticIntField(env, cl_simplesshdservice, fid_sss_sshd_pid); kill(pid, SIGKILL); - (*env)->SetStaticIntField(env, cl_simplesshdservice, fid_sss_sshd_pid, 0); } JNIEXPORT int JNICALL diff --git a/src/org/galexander/sshd/SimpleSSHDService.java b/src/org/galexander/sshd/SimpleSSHDService.java index 5337f84..8024bed 100644 --- a/src/org/galexander/sshd/SimpleSSHDService.java +++ b/src/org/galexander/sshd/SimpleSSHDService.java @@ -9,7 +9,13 @@ import java.io.File; import java.io.FileReader; public class SimpleSSHDService extends Service { - public static int sshd_pid = 0; + /* if restarting twice within 10 seconds, give up */ + private static final int MIN_DURATION = 10000; + + private static final Object lock = new Object(); + private static int sshd_pid = 0; + private static long sshd_when = 0; + private static long sshd_duration = 0; public void onCreate() { super.onCreate(); @@ -17,11 +23,8 @@ public class SimpleSSHDService extends Service { Prefs.init(this); read_pidfile(); - if (is_started()) { - /* would prefer to restart the daemon process rather - * than leave the stale one around.. */ - stop_sshd(); - } + + stop_sshd(); /* it would be stale anyways */ } public int onStartCommand(Intent intent, int flags, int startId) { @@ -48,9 +51,7 @@ public class SimpleSSHDService extends Service { /* unfortunately, android doesn't reliably call this when, i.e., * the package is upgraded... so it's really pretty useless */ public void onDestroy() { - if (is_started()) { - stop_sshd(); - } + stop_sshd(); stopSelf(); super.onDestroy(); } @@ -59,23 +60,55 @@ public class SimpleSSHDService extends Service { return (sshd_pid != 0); } - private void do_start() { - if (is_started()) { - stop_sshd(); + private static void stop_sshd() { + int pid; + synchronized (lock) { + pid = sshd_pid; + sshd_pid = 0; + } + if (pid != 0) { + kill(pid); } - start_sshd(Prefs.get_port(), + } + + private static void maybe_restart(int pid) { + boolean do_restart = false; + long now = System.currentTimeMillis(); + synchronized (lock) { + if (sshd_pid == pid) { + sshd_pid = 0; + do_restart = + ((sshd_duration == 0) || + (sshd_when == 0) || + (sshd_duration >= MIN_DURATION) || + ((now-sshd_when) >= MIN_DURATION)); + } + } + if (do_restart) { + do_start(); + } + } + + private static void do_start() { + stop_sshd(); + final int pid = start_sshd(Prefs.get_port(), Prefs.get_path(), Prefs.get_shell(), Prefs.get_home(), Prefs.get_extra(), (Prefs.get_rsyncbuffer() ? 1 : 0)); - if (sshd_pid != 0) { - final int pid = sshd_pid; + long now = System.currentTimeMillis(); + if (pid != 0) { + synchronized (lock) { + stop_sshd(); + sshd_pid = pid; + sshd_duration = ((sshd_when != 0) + ? (now - sshd_when) : 0); + sshd_when = now; + } (new Thread() { public void run() { waitpid(pid); - if (sshd_pid == pid) { - sshd_pid = 0; - } + maybe_restart(pid); SimpleSSHD.update_startstop(); } }).start(); @@ -86,23 +119,32 @@ public class SimpleSSHDService extends Service { private static void read_pidfile() { try { File f = new File(Prefs.get_path(), "dropbear.pid"); + int pid = 0; if (f.exists()) { BufferedReader r = new BufferedReader( new FileReader(f)); try { - sshd_pid = + pid = Integer.valueOf(r.readLine()); } finally { r.close(); } } + if (pid != 0) { + synchronized (lock) { + stop_sshd(); + sshd_pid = pid; + sshd_when = System.currentTimeMillis(); + sshd_duration = 0; + } + } } catch (Exception e) { /* *shrug* */ } } - private static native void start_sshd(int port, String path, + private static native int start_sshd(int port, String path, String shell, String home, String extra, int rsyncbuffer); - private static native void stop_sshd(); + private static native void kill(int pid); private static native int waitpid(int pid); static { System.loadLibrary("simplesshd-jni");