diff --git a/apps/routerconsole/jsp/nav.jsp b/apps/routerconsole/jsp/nav.jsp
index 87b04ea90..30f694165 100644
--- a/apps/routerconsole/jsp/nav.jsp
+++ b/apps/routerconsole/jsp/nav.jsp
@@ -1,4 +1,10 @@
-<%
+<% response.setHeader("Pragma", "no-cache");
+ response.setHeader("Cache-Control","no-cache");
+ response.setDateHeader("Expires", 0);
+ // the above will b0rk if the servlet engine has already flushed
+ // the response prior to including nav.jsp, so nav should be
+ // near the top
+
if (request.getParameter("i2p.contextId") != null) {
session.setAttribute("i2p.contextId", request.getParameter("i2p.contextId"));
}%>
diff --git a/build.xml b/build.xml
index 45fc30eba..de32698f5 100644
--- a/build.xml
+++ b/build.xml
@@ -206,6 +206,8 @@
+
+
diff --git a/history.txt b/history.txt
index ecef3c003..eac1e0bc0 100644
--- a/history.txt
+++ b/history.txt
@@ -1,4 +1,14 @@
-$Id: history.txt,v 1.5 2004/09/03 14:46:08 jrandom Exp $
+$Id: history.txt,v 1.6 2004/09/04 00:41:42 jrandom Exp $
+
+2004-09-04 jrandom
+ * Added some basic guards to prevent multiple instances from running.
+ Specifically, a file "router.ping" in the install directory which is
+ written to once a minute - if that file exists and has been modified
+ within the last minute, refuse to start up. In turn, adjust the
+ service wrapper to wait a minute before restarting a crashed JVM.
+ * Create a "work" directory in the I2P install dir which Jetty will
+ use for all of its temporary files.
+ * Tell the browser not to cache most of the router console's pages.
2004-09-04 jrandom
* Update the SDK to automatically reconnect indefinitely with an
diff --git a/installer/resources/wrapper.conf b/installer/resources/wrapper.conf
index 494fa17ef..0be599987 100644
--- a/installer/resources/wrapper.conf
+++ b/installer/resources/wrapper.conf
@@ -100,7 +100,7 @@ wrapper.jvm_exit.timeout=60
wrapper.jvm_exit.timeout=30
# give the OS 30s to clear all the old sockets / etc before restarting
-#wrapper.restart.delay=30
+wrapper.restart.delay=60
# use the wrapper's internal timer thread. otherwise this would
# force a restart of the router during daylight savings time as well
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index ac08e216b..0926ad1cb 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -82,6 +82,14 @@ public class Router {
public Router(Properties envProps) { this(null, envProps); }
public Router(String configFilename) { this(configFilename, null); }
public Router(String configFilename, Properties envProps) {
+ if (!beginMarkingLiveliness(envProps)) {
+ System.err.println("ERROR: There appears to be another router already running!");
+ System.err.println(" Please make sure to shut down old instances before starting up");
+ System.err.println(" a new one. If you are positive that no other instance is running,");
+ System.err.println(" please delete the file " + getPingFile(envProps));
+ System.exit(-1);
+ }
+
_config = new Properties();
_context = new RouterContext(this, envProps);
if (configFilename == null)
@@ -554,6 +562,8 @@ public class Router {
dumpStats();
_log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete", new Exception("Shutdown"));
try { _context.logManager().shutdown(); } catch (Throwable t) { }
+ File f = new File(getPingFile());
+ f.delete();
if (_killVMOnEnd) {
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
Runtime.getRuntime().halt(exitCode);
@@ -685,6 +695,77 @@ public class Router {
r.runRouter();
}
+ private static String getPingFile(Properties envProps) {
+ if (envProps != null)
+ return envProps.getProperty("router.pingFile", "router.ping");
+ else
+ return "router.ping";
+ }
+ private String getPingFile() {
+ return _context.getProperty("router.pingFile", "router.ping");
+ }
+
+ private static final long LIVELINESS_DELAY = 60*1000;
+
+ /**
+ * Start a thread that will periodically update the file "router.ping", but if
+ * that file already exists and was recently written to, return false as there is
+ * another instance running
+ *
+ * @return true if the router is the only one running
+ */
+ private boolean beginMarkingLiveliness(Properties envProps) {
+ String filename = getPingFile(envProps);
+ File f = new File(filename);
+ if (f.exists()) {
+ long lastWritten = f.lastModified();
+ if (System.currentTimeMillis()-lastWritten > LIVELINESS_DELAY) {
+ System.err.println("WARN: Old router was not shut down gracefully, deleting router.ping");
+ f.delete();
+ } else {
+ return false;
+ }
+ }
+ // not an I2PThread for context creation issues
+ Thread t = new Thread(new MarkLiveliness(f));
+ t.setName("Mark router liveliness");
+ t.setDaemon(true);
+ t.start();
+ return true;
+ }
+
+ private class MarkLiveliness implements Runnable {
+ private File _pingFile;
+ public MarkLiveliness(File f) {
+ _pingFile = f;
+ }
+ public void run() {
+ _pingFile.deleteOnExit();
+ do {
+ ping();
+ try { Thread.sleep(LIVELINESS_DELAY); } catch (InterruptedException ie) {}
+ } while (_isAlive);
+ _pingFile.delete();
+ }
+
+ private void ping() {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(_pingFile);
+ fos.write(("" + System.currentTimeMillis()).getBytes());
+ } catch (IOException ioe) {
+ if (_log != null) {
+ _log.log(Log.CRIT, "Error writing to ping file", ioe);
+ } else {
+ System.err.println("Error writing to ping file");
+ ioe.printStackTrace();
+ }
+ } finally {
+ if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+ }
+ }
+ }
+
private static int __id = 0;
private class ShutdownHook extends Thread {
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 12c8743d4..63db90c95 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
*
*/
public class RouterVersion {
- public final static String ID = "$Revision: 1.21 $ $Date: 2004/09/03 14:46:07 $";
+ public final static String ID = "$Revision: 1.22 $ $Date: 2004/09/04 00:41:42 $";
public final static String VERSION = "0.4";
- public final static long BUILD = 4;
+ public final static long BUILD = 5;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION);
System.out.println("Router ID: " + RouterVersion.ID);