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)
This commit is contained in:
jrandom
2004-11-21 22:31:33 +00:00
committed by zzz
parent 2c59435762
commit 12a6f3e938
8 changed files with 90 additions and 46 deletions

View File

@ -99,7 +99,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
t.start(); t.start();
open = true; open = true;
synchronized (this) { synchronized (this) {
while (!listenerReady) { while (!listenerReady && open) {
try { try {
wait(); wait();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -112,7 +112,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
l.log("Ready! Port " + getLocalPort()); l.log("Ready! Port " + getLocalPort());
notifyEvent("openBaseClientResult", "ok"); notifyEvent("openBaseClientResult", "ok");
} else { } else {
l.log("Error!"); l.log("Error listening - please see the logs!");
notifyEvent("openBaseClientResult", "error"); notifyEvent("openBaseClientResult", "error");
} }
} }
@ -232,7 +232,13 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
public final void run() { public final void run() {
try { try {
InetAddress addr = getListenHost(l); InetAddress addr = getListenHost(l);
if (addr == null) return; if (addr == null) {
open = false;
synchronized (this) {
notifyAll();
}
return;
}
ss = new ServerSocket(localPort, 0, addr); ss = new ServerSocket(localPort, 0, addr);
// If a free port was requested, find out what we got // 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); manageConnection(s);
} }
} catch (IOException ex) { } catch (IOException ex) {
_log.error("Error listening for connections", ex); _log.error("Error listening for connections on " + localPort, ex);
notifyEvent("openBaseClientResult", "error"); notifyEvent("openBaseClientResult", "error");
synchronized (sockLock) { synchronized (sockLock) {
mySockets.clear(); mySockets.clear();
} }
open = false;
synchronized (this) {
notifyAll();
}
} }
} }

View File

@ -31,6 +31,7 @@ public class TunnelController implements Logging {
private List _messages; private List _messages;
private List _sessions; private List _sessions;
private boolean _running; private boolean _running;
private boolean _starting;
/** /**
* Create a new controller for a tunnel out of the specific config options. * Create a new controller for a tunnel out of the specific config options.
@ -58,8 +59,7 @@ public class TunnelController implements Logging {
_running = false; _running = false;
if (createKey && ("server".equals(getType())) ) if (createKey && ("server".equals(getType())) )
createPrivateKey(); createPrivateKey();
if (getStartOnLoad()) _starting = getStartOnLoad();
startTunnel();
} }
private void createPrivateKey() { private void createPrivateKey() {
@ -104,12 +104,14 @@ public class TunnelController implements Logging {
* *
*/ */
public void startTunnel() { public void startTunnel() {
_starting = true;
try { try {
doStartTunnel(); doStartTunnel();
} catch (Exception e) { } catch (Exception e) {
_log.error("Error starting up the tunnel", e); _log.error("Error starting up the tunnel", e);
log("Error starting up the tunnel - " + e.getMessage()); log("Error starting up the tunnel - " + e.getMessage());
} }
_starting = false;
} }
private void doStartTunnel() { private void doStartTunnel() {
if (_running) { if (_running) {
@ -299,6 +301,7 @@ public class TunnelController implements Logging {
public boolean getStartOnLoad() { return "true".equalsIgnoreCase(_config.getProperty("startOnLoad", "true")); } public boolean getStartOnLoad() { return "true".equalsIgnoreCase(_config.getProperty("startOnLoad", "true")); }
public boolean getIsRunning() { return _running; } public boolean getIsRunning() { return _running; }
public boolean getIsStarting() { return _starting; }
public void getSummary(StringBuffer buf) { public void getSummary(StringBuffer buf) {
String type = getType(); String type = getType();

View File

@ -8,6 +8,7 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -20,6 +21,8 @@ import java.util.TreeMap;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession; import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException; import net.i2p.client.I2PSessionException;
import net.i2p.data.DataHelper;
import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
@ -43,28 +46,34 @@ public class TunnelControllerGroup {
*/ */
private Map _sessions; 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) { private TunnelControllerGroup(String configFile) {
_log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelControllerGroup.class); _log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelControllerGroup.class);
_instance = this; _controllers = Collections.synchronizedList(new ArrayList());
_controllers = new ArrayList();
_configFile = configFile; _configFile = configFile;
_sessions = new HashMap(4); _sessions = new HashMap(4);
loadControllers(_configFile); loadControllers(_configFile);
} }
public static void main(String args[]) { public static void main(String args[]) {
if ( (args == null) || (args.length <= 0) ) { synchronized (TunnelControllerGroup.class) {
new TunnelControllerGroup(DEFAULT_CONFIG_FILE); if (_instance != null) return; // already loaded through the web
} else if (args.length == 1) {
if (DEFAULT_CONFIG_FILE.equals(args[0])) if ( (args == null) || (args.length <= 0) ) {
new TunnelControllerGroup(DEFAULT_CONFIG_FILE); _instance = new TunnelControllerGroup(DEFAULT_CONFIG_FILE);
else } else if (args.length == 1) {
new TunnelControllerGroup(args[0]); _instance = new TunnelControllerGroup(args[0]);
} else { } else {
System.err.println("Usage: TunnelControllerGroup [filename]"); System.err.println("Usage: TunnelControllerGroup [filename]");
return; return;
}
} }
} }
@ -89,10 +98,24 @@ public class TunnelControllerGroup {
_controllers.add(controller); _controllers.add(controller);
i++; i++;
} }
I2PThread startupThread = new I2PThread(new StartControllers(), "Startup tunnels");
startupThread.start();
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(i + " controllers loaded from " + configFile); _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() { public void reloadControllers() {
unloadControllers(); unloadControllers();
loadControllers(_configFile); loadControllers(_configFile);
@ -143,7 +166,6 @@ public class TunnelControllerGroup {
controller.stopTunnel(); controller.stopTunnel();
msgs.addAll(controller.clearMessages()); msgs.addAll(controller.clearMessages());
} }
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers stopped"); _log.info(_controllers.size() + " controllers stopped");
return msgs; return msgs;
@ -161,7 +183,7 @@ public class TunnelControllerGroup {
controller.startTunnel(); controller.startTunnel();
msgs.addAll(controller.clearMessages()); msgs.addAll(controller.clearMessages());
} }
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers started"); _log.info(_controllers.size() + " controllers started");
return msgs; return msgs;
@ -259,33 +281,13 @@ public class TunnelControllerGroup {
} }
Properties props = new Properties(); Properties props = new Properties();
FileInputStream fis = null;
try { try {
fis = new FileInputStream(cfgFile); DataHelper.loadProps(props, 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");
return props; return props;
} catch (IOException ioe) { } catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("Error reading the controllers from " + configFile, ioe); _log.error("Error reading the controllers from " + configFile, ioe);
return null; return null;
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
} }
} }

View File

@ -68,6 +68,8 @@ public class WebStatusPageHelper {
if (controller.getIsRunning()) { if (controller.getIsRunning()) {
buf.append("<i>running</i> "); buf.append("<i>running</i> ");
buf.append("<a href=\"index.jsp?num=").append(num).append("&action=stop\">stop</a> "); buf.append("<a href=\"index.jsp?num=").append(num).append("&action=stop\">stop</a> ");
} else if (controller.getIsStarting()) {
buf.append("<i>startup in progress (please be patient)</i>");
} else { } else {
buf.append("<i>not running</i> "); buf.append("<i>not running</i> ");
buf.append("<a href=\"index.jsp?num=").append(num).append("&action=start\">start</a> "); buf.append("<a href=\"index.jsp?num=").append(num).append("&action=start\">start</a> ");

View File

@ -250,6 +250,7 @@ public class SAMBridge implements Runnable {
} }
public void run() { public void run() {
if (serverSocket == null) return;
try { try {
while (acceptConnections) { while (acceptConnections) {
Socket s = serverSocket.accept(); Socket s = serverSocket.accept();
@ -293,7 +294,8 @@ public class SAMBridge implements Runnable {
try { try {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Shutting down, closing server socket"); _log.debug("Shutting down, closing server socket");
serverSocket.close(); if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {} } catch (IOException e) {}
} }
} }

View File

@ -17,6 +17,7 @@ import net.i2p.time.Timestamper;
public class Clock implements Timestamper.UpdateListener { public class Clock implements Timestamper.UpdateListener {
private I2PAppContext _context; private I2PAppContext _context;
private Timestamper _timestamper; private Timestamper _timestamper;
private long _startedOn;
public Clock(I2PAppContext context) { public Clock(I2PAppContext context) {
_context = context; _context = context;
@ -24,6 +25,7 @@ public class Clock implements Timestamper.UpdateListener {
_alreadyChanged = false; _alreadyChanged = false;
_listeners = new HashSet(64); _listeners = new HashSet(64);
_timestamper = new Timestamper(context, this); _timestamper = new Timestamper(context, this);
_startedOn = System.currentTimeMillis();
} }
public static Clock getInstance() { public static Clock getInstance() {
return I2PAppContext.getGlobalContext().clock(); return I2PAppContext.getGlobalContext().clock();
@ -40,6 +42,8 @@ public class Clock implements Timestamper.UpdateListener {
/** if the clock is skewed by 3+ days, fuck 'em */ /** if the clock is skewed by 3+ days, fuck 'em */
public final static long MAX_OFFSET = 3 * 24 * 60 * 60 * 1000; 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) */ /** 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; public final static long MIN_OFFSET_CHANGE = 10 * 1000;
@ -60,6 +64,15 @@ public class Clock implements Timestamper.UpdateListener {
return; 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)) { if ((delta < MIN_OFFSET_CHANGE) && (delta > 0 - MIN_OFFSET_CHANGE)) {
getLog().debug("Not changing offset since it is only " + delta + "ms"); getLog().debug("Not changing offset since it is only " + delta + "ms");
return; return;

View File

@ -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 2004-11-21 jrandom
* Allow end of line comments in the hosts.txt and other config files, * Allow end of line comments in the hosts.txt and other config files,

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
* *
*/ */
public class RouterVersion { 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 String VERSION = "0.4.1.4";
public final static long BUILD = 11; public final static long BUILD = 12;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION); System.out.println("I2P Router version: " + VERSION);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);