From 12a6f3e9388df0ccb53fff2246812acaa97799a7 Mon Sep 17 00:00:00 2001 From: jrandom Date: Sun, 21 Nov 2004 22:31:33 +0000 Subject: [PATCH] 2004-11-21 jrandom * Only allow small clock skews after the first 10 minutes of operation (to prevent later network lag bouncing us way off course - yes, we really need an NTP impl to balance out the network burps...) * Revamp the I2PTunnel web interface startup process so that everything is shown immediately, so that different pieces hanging don't hang the rest, and other minor bugfixes. * Take note of SAM startup error (in case you're already running a SAM bridge...) * Increase the bandwidth limiter burst values available to 10-60s (or whatever is placed in /configadvanced.jsp, of course) --- .../i2p/i2ptunnel/I2PTunnelClientBase.java | 18 ++++- .../net/i2p/i2ptunnel/TunnelController.java | 7 +- .../i2p/i2ptunnel/TunnelControllerGroup.java | 74 ++++++++++--------- .../i2p/i2ptunnel/WebStatusPageHelper.java | 2 + apps/sam/java/src/net/i2p/sam/SAMBridge.java | 4 +- core/java/src/net/i2p/util/Clock.java | 13 ++++ history.txt | 14 +++- .../src/net/i2p/router/RouterVersion.java | 4 +- 8 files changed, 90 insertions(+), 46 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index 08ac271b7..00a210a8a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -99,7 +99,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna t.start(); open = true; synchronized (this) { - while (!listenerReady) { + while (!listenerReady && open) { try { wait(); } catch (InterruptedException e) { @@ -112,7 +112,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna l.log("Ready! Port " + getLocalPort()); notifyEvent("openBaseClientResult", "ok"); } else { - l.log("Error!"); + l.log("Error listening - please see the logs!"); notifyEvent("openBaseClientResult", "error"); } } @@ -232,7 +232,13 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna public final void run() { try { InetAddress addr = getListenHost(l); - if (addr == null) return; + if (addr == null) { + open = false; + synchronized (this) { + notifyAll(); + } + return; + } ss = new ServerSocket(localPort, 0, addr); // If a free port was requested, find out what we got @@ -263,11 +269,15 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna manageConnection(s); } } catch (IOException ex) { - _log.error("Error listening for connections", ex); + _log.error("Error listening for connections on " + localPort, ex); notifyEvent("openBaseClientResult", "error"); synchronized (sockLock) { mySockets.clear(); } + open = false; + synchronized (this) { + notifyAll(); + } } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index b486185c6..03379accf 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -31,6 +31,7 @@ public class TunnelController implements Logging { private List _messages; private List _sessions; private boolean _running; + private boolean _starting; /** * Create a new controller for a tunnel out of the specific config options. @@ -58,8 +59,7 @@ public class TunnelController implements Logging { _running = false; if (createKey && ("server".equals(getType())) ) createPrivateKey(); - if (getStartOnLoad()) - startTunnel(); + _starting = getStartOnLoad(); } private void createPrivateKey() { @@ -104,12 +104,14 @@ public class TunnelController implements Logging { * */ public void startTunnel() { + _starting = true; try { doStartTunnel(); } catch (Exception e) { _log.error("Error starting up the tunnel", e); log("Error starting up the tunnel - " + e.getMessage()); } + _starting = false; } private void doStartTunnel() { if (_running) { @@ -299,6 +301,7 @@ public class TunnelController implements Logging { public boolean getStartOnLoad() { return "true".equalsIgnoreCase(_config.getProperty("startOnLoad", "true")); } public boolean getIsRunning() { return _running; } + public boolean getIsStarting() { return _starting; } public void getSummary(StringBuffer buf) { String type = getType(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java index eb1a42676..2978c9921 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -20,6 +21,8 @@ import java.util.TreeMap; import net.i2p.I2PAppContext; import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; +import net.i2p.data.DataHelper; +import net.i2p.util.I2PThread; import net.i2p.util.Log; /** @@ -43,28 +46,34 @@ public class TunnelControllerGroup { */ private Map _sessions; - public static TunnelControllerGroup getInstance() { return _instance; } + public static TunnelControllerGroup getInstance() { + synchronized (TunnelControllerGroup.class) { + if (_instance == null) + _instance = new TunnelControllerGroup(DEFAULT_CONFIG_FILE); + return _instance; + } + } private TunnelControllerGroup(String configFile) { _log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelControllerGroup.class); - _instance = this; - _controllers = new ArrayList(); + _controllers = Collections.synchronizedList(new ArrayList()); _configFile = configFile; _sessions = new HashMap(4); loadControllers(_configFile); } public static void main(String args[]) { - if ( (args == null) || (args.length <= 0) ) { - new TunnelControllerGroup(DEFAULT_CONFIG_FILE); - } else if (args.length == 1) { - if (DEFAULT_CONFIG_FILE.equals(args[0])) - new TunnelControllerGroup(DEFAULT_CONFIG_FILE); - else - new TunnelControllerGroup(args[0]); - } else { - System.err.println("Usage: TunnelControllerGroup [filename]"); - return; + synchronized (TunnelControllerGroup.class) { + if (_instance != null) return; // already loaded through the web + + if ( (args == null) || (args.length <= 0) ) { + _instance = new TunnelControllerGroup(DEFAULT_CONFIG_FILE); + } else if (args.length == 1) { + _instance = new TunnelControllerGroup(args[0]); + } else { + System.err.println("Usage: TunnelControllerGroup [filename]"); + return; + } } } @@ -89,10 +98,24 @@ public class TunnelControllerGroup { _controllers.add(controller); i++; } + I2PThread startupThread = new I2PThread(new StartControllers(), "Startup tunnels"); + startupThread.start(); + if (_log.shouldLog(Log.INFO)) _log.info(i + " controllers loaded from " + configFile); } + private class StartControllers implements Runnable { + public void run() { + for (int i = 0; i < _controllers.size(); i++) { + TunnelController controller = (TunnelController)_controllers.get(i); + if (controller.getStartOnLoad()) + controller.startTunnel(); + } + } + } + + public void reloadControllers() { unloadControllers(); loadControllers(_configFile); @@ -143,7 +166,6 @@ public class TunnelControllerGroup { controller.stopTunnel(); msgs.addAll(controller.clearMessages()); } - if (_log.shouldLog(Log.INFO)) _log.info(_controllers.size() + " controllers stopped"); return msgs; @@ -161,7 +183,7 @@ public class TunnelControllerGroup { controller.startTunnel(); msgs.addAll(controller.clearMessages()); } - + if (_log.shouldLog(Log.INFO)) _log.info(_controllers.size() + " controllers started"); return msgs; @@ -259,33 +281,13 @@ public class TunnelControllerGroup { } Properties props = new Properties(); - FileInputStream fis = null; try { - fis = new FileInputStream(cfgFile); - BufferedReader in = new BufferedReader(new InputStreamReader(fis)); - String line = null; - while ( (line = in.readLine()) != null) { - line = line.trim(); - if (line.length() <= 0) continue; - if (line.startsWith("#") || line.startsWith(";")) - continue; - int eq = line.indexOf('='); - if ( (eq <= 0) || (eq >= line.length() - 1) ) - continue; - String key = line.substring(0, eq); - String val = line.substring(eq+1); - props.setProperty(key, val); - } - - if (_log.shouldLog(Log.INFO)) - _log.info("Props loaded with " + props.size() + " lines"); + DataHelper.loadProps(props, cfgFile); return props; } catch (IOException ioe) { if (_log.shouldLog(Log.ERROR)) _log.error("Error reading the controllers from " + configFile, ioe); return null; - } finally { - if (fis != null) try { fis.close(); } catch (IOException ioe) {} } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/WebStatusPageHelper.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/WebStatusPageHelper.java index c186a1857..07d55f88a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/WebStatusPageHelper.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/WebStatusPageHelper.java @@ -68,6 +68,8 @@ public class WebStatusPageHelper { if (controller.getIsRunning()) { buf.append("running "); buf.append("stop "); + } else if (controller.getIsStarting()) { + buf.append("startup in progress (please be patient)"); } else { buf.append("not running "); buf.append("start "); diff --git a/apps/sam/java/src/net/i2p/sam/SAMBridge.java b/apps/sam/java/src/net/i2p/sam/SAMBridge.java index fe95b297d..c1dd7fe8a 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMBridge.java +++ b/apps/sam/java/src/net/i2p/sam/SAMBridge.java @@ -250,6 +250,7 @@ public class SAMBridge implements Runnable { } public void run() { + if (serverSocket == null) return; try { while (acceptConnections) { Socket s = serverSocket.accept(); @@ -293,7 +294,8 @@ public class SAMBridge implements Runnable { try { if (_log.shouldLog(Log.DEBUG)) _log.debug("Shutting down, closing server socket"); - serverSocket.close(); + if (serverSocket != null) + serverSocket.close(); } catch (IOException e) {} } } diff --git a/core/java/src/net/i2p/util/Clock.java b/core/java/src/net/i2p/util/Clock.java index 61ae7c402..0a1c0662b 100644 --- a/core/java/src/net/i2p/util/Clock.java +++ b/core/java/src/net/i2p/util/Clock.java @@ -17,6 +17,7 @@ import net.i2p.time.Timestamper; public class Clock implements Timestamper.UpdateListener { private I2PAppContext _context; private Timestamper _timestamper; + private long _startedOn; public Clock(I2PAppContext context) { _context = context; @@ -24,6 +25,7 @@ public class Clock implements Timestamper.UpdateListener { _alreadyChanged = false; _listeners = new HashSet(64); _timestamper = new Timestamper(context, this); + _startedOn = System.currentTimeMillis(); } public static Clock getInstance() { return I2PAppContext.getGlobalContext().clock(); @@ -40,6 +42,8 @@ public class Clock implements Timestamper.UpdateListener { /** if the clock is skewed by 3+ days, fuck 'em */ public final static long MAX_OFFSET = 3 * 24 * 60 * 60 * 1000; + /** after we've started up and shifted the clock, don't allow shifts of more than a minute */ + public final static long MAX_LIVE_OFFSET = 60 * 1000; /** if the clock skewed changes by less than 1s, ignore the update (so we don't slide all over the place) */ public final static long MIN_OFFSET_CHANGE = 10 * 1000; @@ -60,6 +64,15 @@ public class Clock implements Timestamper.UpdateListener { return; } + // only allow substantial modifications before the first 10 minutes + if (_alreadyChanged && (System.currentTimeMillis() - _startedOn > 10 * 60 * 1000)) { + if ( (offsetMs > MAX_LIVE_OFFSET) || (offsetMs < 0 - MAX_LIVE_OFFSET) ) { + getLog().log(Log.CRIT, "The clock has already been updated, but you want to change it by " + + offsetMs + "? Did something break?"); + return; + } + } + if ((delta < MIN_OFFSET_CHANGE) && (delta > 0 - MIN_OFFSET_CHANGE)) { getLog().debug("Not changing offset since it is only " + delta + "ms"); return; diff --git a/history.txt b/history.txt index 49e9ce30b..b4f7cae87 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,16 @@ -$Id: history.txt,v 1.77 2004/11/20 23:08:14 jrandom Exp $ +$Id: history.txt,v 1.78 2004/11/21 14:42:57 jrandom Exp $ + +2004-11-21 jrandom + * Only allow small clock skews after the first 10 minutes of operation + (to prevent later network lag bouncing us way off course - yes, we + really need an NTP impl to balance out the network burps...) + * Revamp the I2PTunnel web interface startup process so that everything + is shown immediately, so that different pieces hanging don't hang + the rest, and other minor bugfixes. + * Take note of SAM startup error (in case you're already running a SAM + bridge...) + * Increase the bandwidth limiter burst values available to 10-60s (or + whatever is placed in /configadvanced.jsp, of course) 2004-11-21 jrandom * Allow end of line comments in the hosts.txt and other config files, diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index bf30d4d53..f53712c3c 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.82 $ $Date: 2004/11/20 23:08:14 $"; + public final static String ID = "$Revision: 1.83 $ $Date: 2004/11/21 14:42:58 $"; public final static String VERSION = "0.4.1.4"; - public final static long BUILD = 11; + public final static long BUILD = 12; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID);