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);