diff --git a/router/java/src/net/i2p/router/MultiRouter.java b/router/java/src/net/i2p/router/MultiRouter.java
index 43f618bc2..bee66b258 100644
--- a/router/java/src/net/i2p/router/MultiRouter.java
+++ b/router/java/src/net/i2p/router/MultiRouter.java
@@ -1,11 +1,18 @@
package net.i2p.router;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Properties;
+import java.util.Scanner;
import net.i2p.I2PAppContext;
+import net.i2p.data.DataHelper;
+import net.i2p.data.RouterInfo;
+import net.i2p.router.Router;
import net.i2p.util.Log;
/**
@@ -16,7 +23,7 @@ import net.i2p.util.Log;
* contained in them are used for the context's getProperty(name)).
*
* Usage:
- * MultiRouter globalContextFile routerContextFile[ routerContextFile]*
+ * MultiRouter numberRouters
*
*
* Each routerContext specified is used to boot up a single router. It is HIGHLY
@@ -36,72 +43,181 @@ import net.i2p.util.Log;
* that need the encryption enabled). To run a client app through a router that
* has i2p.encryption=off, you should also add that line to the client's JVM
* (for example, java -Di2p.encryption=off -jar lib/i2ptunnel.jar).
+ *
+ * To make the router console work, either run from a directory containing
+ * lib/, webapps/, docs/, etc., or point i2p.dir.base to a directory containing the
+ * above.
*
* The multirouter waits until all of the routers are shut down (which none will
* do on their own, so as before, you'll want to kill the proc or ^C it).
*/
public class MultiRouter {
- private static Log _log;
- private static ArrayList _routers = new ArrayList(8);
+
+ private static final int BASE_PORT = 5000;
+
+ private static int nbrRouters;
+
+ private static PrintStream _out;
+ private static ArrayList _routers = new ArrayList(8);
private static I2PAppContext _defaultContext;
public static void main(String args[]) {
- if ( (args == null) || (args.length <= 1) ) {
+ if ( (args == null) || (args.length < 1) ) {
+ usage();
+ return;
+ }
+ Scanner scan = new Scanner(args[0]);
+ if (!scan.hasNextInt()) {
+ usage();
+ return;
+ }
+ nbrRouters = scan.nextInt();
+ if (nbrRouters < 0) {
usage();
return;
}
- _defaultContext = new I2PAppContext(getEnv(args[0]));
-
- _log = _defaultContext.logManager().getLog(MultiRouter.class);
- try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
+ _out = System.out;
+
+ buildClientProps(0);
+ _defaultContext = new I2PAppContext(buildRouterProps(0));
_defaultContext.clock().setOffset(0);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
- Thread.currentThread().setName("Router* Shutdown");
- try { Thread.sleep(120*1000); } catch (InterruptedException ie) {}
- Runtime.getRuntime().halt(-1);
+ _out.println("Shutting down in a few moments..");
+ for(Router r : _routers) {
+ r.shutdown(-1);
+ }
+ try { Thread.sleep(1500); } catch (InterruptedException ie) {}
+ Runtime.getRuntime().halt(0);
}
});
- for (int i = 1; i < args.length; i++) {
- Router router = new Router(getEnv(args[i]));
+ for (int i = 0; i < nbrRouters; i++) {
+ Router router = new Router(buildRouterProps(i));
router.setKillVMOnEnd(false);
_routers.add(router);
- _log.info("Router " + i + " created from " + args[i]);
- //try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
+ _out.println("Router " + i + " was created");
}
- for (int i = 0; i < _routers.size(); i++) {
- Router r = (Router)_routers.get(i);
+ for (int i = 0; i < nbrRouters; i++) {
+ Router r = _routers.get(i);
long offset = r.getContext().random().nextLong(Router.CLOCK_FUDGE_FACTOR/2);
if (r.getContext().random().nextBoolean())
offset = 0 - offset;
r.getContext().clock().setOffset(offset, true);
r.runRouter();
- _log.info("Router " + i + " started with clock offset " + offset);
- try { Thread.sleep(2*1000 + new java.util.Random().nextInt(2)*1000); } catch (InterruptedException ie) {}
+ _out.println("Router " + i + " was started with time offset " + offset);
}
- _log.info("All " + _routers.size() + " routers started up");
+ _out.println("All routers have been started");
+
+ /* Wait for routers to start services and generate keys.. */
+ try { Thread.sleep(1000); } catch (InterruptedException ie) {}
+ internalReseed();
+
waitForCompletion();
}
- private static Properties getEnv(String filename) {
- Properties props = new Properties();
- FileInputStream in = null;
- try {
- in = new FileInputStream(filename);
- props.load(in);
- props.setProperty("time.disabled", "true");
- return props;
- } catch (IOException ioe) {
- ioe.printStackTrace();
- return null;
- } finally {
- if (in != null) try { in.close(); } catch (IOException ioe) {}
+ private static void internalReseed() {
+
+ HashSet riSet = new HashSet();
+ for(Router r : _routers) {
+ riSet.addAll(r.getContext().netDb().getRouters());
+ }
+ for(Router r : _routers) {
+ for(RouterInfo ri : riSet){
+ r.getContext().netDb().publish(ri);
+ }
+ }
+ _out.println(riSet.size() + " RouterInfos were reseeded");
+ }
+
+ private static Properties buildRouterProps(int id) {
+ Properties props = getRouterProps(id);
+ File f = new File(props.getProperty("router.configLocation"));
+ f.getParentFile().mkdirs();
+ if (!f.exists()) {
+ try {
+ DataHelper.storeProps(props, f);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
+ return props;
+ }
+
+ private static Properties getRouterProps(int id) {
+ Properties props = new Properties();
+
+ props.setProperty("router.profileDir", "/peerProfiles");
+ props.setProperty("router.sessionKeys.location", "/sessionKeys.dat");
+ props.setProperty("router.info.location", "/router.info");
+ props.setProperty("router.keys.location", "/router.keys");
+ props.setProperty("router.networkDatabase.dbDir", "/netDb");
+ props.setProperty("router.tunnelPoolFile", "/tunnelPool.dat");
+ props.setProperty("router.keyBackupDir", "/keyBackup");
+ props.setProperty("router.clientConfigFile", getBaseDir(id) + "/clients.config");
+ props.setProperty("router.configLocation", getBaseDir(id) + "/router.config");
+ props.setProperty("router.pingFile", getBaseDir(id) + "/router.ping");
+ props.setProperty("router.rejectStartupTime", "0");
+ props.setProperty("router.reseedDisable", "true");
+ props.setProperty("i2p.dir.app", getBaseDir(id));
+
+ /* If MultiRouter is not run from a dir containing lib/, webapps/, docs/, etc.
+ * point i2p.dir.base to a directory containing the above. */
+ //props.setProperty("i2p.dir.base", getBaseDir(id));
+ props.setProperty("i2p.dir.config", getBaseDir(id));
+ props.setProperty("i2p.dir.log", getBaseDir(id));
+ props.setProperty("i2p.dir.router", getBaseDir(id));
+ props.setProperty("i2p.dir.pid", getBaseDir(id));
+ //props.setProperty("i2p.vmCommSystem", "true");
+ props.setProperty("i2np.ntcp.hostname", "127.0.0.1");
+ props.setProperty("i2np.udp.host", "127.0.0.1");
+ props.setProperty("i2np.ntcp.port", BASE_PORT + id + "");
+ props.setProperty("i2np.udp.port", BASE_PORT + id + "");
+ props.setProperty("i2np.ntcp.allowLocal", "true");
+ props.setProperty("i2np.udp.allowLocal", "true");
+ props.setProperty("i2np.udp.internalPort", BASE_PORT + id + "");
+ props.setProperty("i2cp.port", Integer.toString((BASE_PORT + nbrRouters + id)));
+
+ return props;
+ }
+
+ private static Properties buildClientProps(int id) {
+ Properties rProps = getRouterProps(id);
+ Properties props = getClientProps();
+ File f = new File(rProps.getProperty("router.clientConfigFile"));
+ f.getParentFile().mkdirs();
+ if (!f.exists()) {
+ try {
+ DataHelper.storeProps(props, f);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return props;
+ }
+
+ private static Properties getClientProps() {
+ Properties props = new Properties();
+
+ props.setProperty("clientApp.0.args", (BASE_PORT-1) + " 127.0.0.1 ./webapps");
+ props.setProperty("clientApp.0.main", "net.i2p.router.web.RouterConsoleRunner");
+ props.setProperty("clientApp.0.name", "webconsole");
+ props.setProperty("clientApp.0.onBoot", "true");
+ props.setProperty("clientApp.1.args", "i2ptunnel.config");
+ props.setProperty("clientApp.1.main", "net.i2p.i2ptunnel.TunnelControllerGroup");
+ props.setProperty("clientApp.1.name", "tunnels");
+ props.setProperty("clientApp.1.delay", "6");
+
+ return props;
+ }
+
+ private static String getBaseDir(int id) {
+ File f = new File(".");
+ return f.getAbsoluteFile().getParentFile().toString() + "/multirouter/"+ Integer.toString(id);
}
private static void waitForCompletion() {
@@ -110,8 +226,7 @@ public class MultiRouter {
for (int i = 0; i < _routers.size(); i++) {
Router r = (Router)_routers.get(i);
if (!r.isAlive()) {
- if (_log.shouldLog(Log.INFO))
- _log.info("Router " + i + " is dead");
+ _out.println("Router " + i + " is dead");
} else {
alive++;
}
@@ -122,13 +237,11 @@ public class MultiRouter {
break;
}
}
- _log.info("All routers shut down");
+ _out.println("All routers shut down");
}
private static void usage() {
- System.err.println("Usage: MultiRouter globalContextFile routerContextFile[ routerContextFile]*");
- System.err.println(" The context files contain key=value entries specifying properties");
- System.err.println(" to load into the given context. In addition, each routerContextFile");
- System.err.println(" in turn is used to boot a router");
+ System.err.println("Usage: MultiRouter nbr_routers");
+ System.err.println(" Where nbr_routers > 0");
}
}
diff --git a/router/java/src/net/i2p/router/MultiRouterBuilder.java b/router/java/src/net/i2p/router/MultiRouterBuilder.java
deleted file mode 100644
index 6a7c635bc..000000000
--- a/router/java/src/net/i2p/router/MultiRouterBuilder.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package net.i2p.router;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Build a set of config files suitable for use by the multirouter as a
- * simulation, as well as a pair of scripts for running the simulation.
- * Usage:
- * MultiRouterBuilder [routerDir routerPortStart]*
- *
- *
- * Each router is configured with their own $routerDir/router.config file so
- * that all of its data is stored under the $routerDir (profiles, keys, netDb,
- * etc). In addition, each router has the i2cp port set to $routerPortStart+1,
- * the admin port set to $routerPortStart+2, and some commented out clientApp
- * lines (configured with the SAM bridge at $routerPortStart+3 and an EepProxy at
- * $routerPortStart+4).
- *
- * It then builds a $routerDir/heartbeat.config containing the following lines:
- * - i2cpHost=localhost
- * - i2cpPort=$routerPortStart+1
- * - numHops=2
- * - privateDestinationFile=$routerDir/heartbeat.keys
- * - publicDestinationFile=$routerDir/heartbeat.txt
- *
- *
- * Then it goes on to create the $routerDir/routerEnv.txt:
- * - loggerFilenameOverride=$routerDir/logs/log-router-#.txt
- * - router.configLocation=$routerDir/router.config
- * - i2p.vmCommSystem=true
- * - i2p.encryption=off
- *
- *
- * In addition, it creates a baseEnv.txt:
- * - loggerFilenameOverride=logs/log-base-#.txt
- *
- *
- * Finally, it creates the MultiRouter startup script to launch all of these
- * routers, stored at runNetSim.bat / runNetSim.sh
- *
- */
-public class MultiRouterBuilder {
- public static void main(String args[]) {
- if (args.length < 2) {
- usage();
- return;
- }
- for (int i = 0; i < args.length; i += 2) {
- String dir = args[i];
- try {
- int basePortNum = Integer.parseInt(args[i+1]);
- buildConfig(dir, basePortNum, i == 0);
- } catch (NumberFormatException nfe) {
- nfe.printStackTrace();
- }
- }
- buildBaseEnv();
- buildStartupScript(args);
- }
-
- private static void buildBaseEnv() {
- File envFile = new File("baseEnv.txt");
- try {
- FileOutputStream fos = new FileOutputStream(envFile);
- fos.write(("loggerFilenameOverride=logs/log-base-#.txt\n").getBytes());
- fos.close();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- File f = new File("logs");
- f.mkdirs();
- }
-
- private static void buildStartupScript(String args[]) {
- buildStartupScriptNix(args);
- }
- private static void buildStartupScriptNix(String args[]) {
- StringBuilder buf = new StringBuilder(4096);
- buf.append("#!/bin/sh\n");
- buf.append("export CP=.; for LIB in lib/* ; do export CP=$CP:$LIB ; done\n");
- buf.append("nohup java -cp $CP ");
- buf.append(" -Xmx1024m");
- buf.append(" -Djava.library.path=.");
- buf.append(" -DloggerFilenameOverride=logs/log-sim-#.txt");
- buf.append(" -Dorg.mortbay.http.Version.paranoid=true");
- buf.append(" -Dorg.mortbay.util.FileResource.checkAliases=false");
- buf.append(" -verbose:gc");
-
- buf.append(" net.i2p.router.MultiRouter baseEnv.txt ");
- for (int i = 0; i < args.length; i += 2)
- buf.append(args[i]).append("/routerEnv.txt ");
- buf.append(" > sim.out 2>&1 &\n");
- buf.append("echo $! > sim.pid\n");
- buf.append("echo \"After all of the routers have started up, you should cross seed them\"\n");
- buf.append("echo \"Simply copy */netDb/routerInfo-* to all of the various */netDb/ directories\"\n");
- try {
- FileOutputStream fos = new FileOutputStream("runNetSim.sh");
- fos.write(buf.toString().getBytes());
- fos.close();
- } catch (IOException ioe) { ioe.printStackTrace(); }
- }
-
- private static void buildConfig(String dir, int basePort, boolean isFirst) {
- File baseDir = new File(dir);
- baseDir.mkdirs();
- File cfgFile = new File(baseDir, "router.config");
- StringBuilder buf = new StringBuilder(8*1024);
- buf.append("router.profileDir=").append(baseDir.getPath()).append("/peerProfiles\n");
- buf.append("router.historyFilename=").append(baseDir.getPath()).append("/messageHistory.txt\n");
- buf.append("router.sessionKeys.location=").append(baseDir.getPath()).append("/sessionKeys.dat\n");
- buf.append("router.info.location=").append(baseDir.getPath()).append("/router.info\n");
- buf.append("router.keys.location=").append(baseDir.getPath()).append("/router.keys\n");
- buf.append("router.networkDatabase.dbDir=").append(baseDir.getPath()).append("/netDb\n");
- buf.append("router.tunnelPoolFile=").append(baseDir.getPath()).append("/tunnelPool.dat\n");
- buf.append("router.keyBackupDir=").append(baseDir.getPath()).append("/keyBackup\n");
- buf.append("router.clientConfigFile=").append(baseDir.getPath()).append("/clients.config\n");
- buf.append("i2np.tcp.port=").append(basePort).append('\n');
- buf.append("i2np.tcp.hostname=localhost\n");
- buf.append("i2np.tcp.allowLocal=true\n");
- buf.append("i2np.tcp.disable=true\n");
- buf.append("i2np.tcp.enable=false\n");
- buf.append("i2np.udp.host=127.0.0.1\n");
- buf.append("i2np.udp.port=").append(basePort).append('\n');
- buf.append("i2np.udp.internalPort=").append(basePort).append('\n');
- buf.append("i2cp.port=").append(basePort+1).append('\n');
- buf.append("stat.logFile=").append(baseDir.getPath()).append("/stats.log\n");
- buf.append("stat.logFilters=*\n");
-
- try {
- FileOutputStream fos = new FileOutputStream(cfgFile);
- fos.write(buf.toString().getBytes());
- fos.close();
-
- File envFile = new File(baseDir, "routerEnv.txt");
- fos = new FileOutputStream(envFile);
- fos.write(("loggerFilenameOverride="+baseDir+ "/logs/log-router-#.txt\n").getBytes());
- fos.write(("router.configLocation="+baseDir+"/router.config\n").getBytes());
- fos.write(("router.pingFile="+baseDir+"/router.ping\n").getBytes());
- //fos.write(("i2p.vmCommSystem=true\n").getBytes());
- //fos.write(("i2p.encryption=off\n").getBytes());
- fos.close();
-
- File f = new File(baseDir, "logs");
- f.mkdirs();
-
- if (isFirst) {
- fos = new FileOutputStream(baseDir.getPath() + "/clients.config");
- fos.write(("clientApp.0.args=" + (basePort-1) + " 127.0.0.1 ./webapps\n").getBytes());
- fos.write(("clientApp.0.main=net.i2p.router.web.RouterConsoleRunner\n").getBytes());
- fos.write(("clientApp.0.name=webconsole\n").getBytes());
- fos.write(("clientApp.0.onBoot=true\n").getBytes());
- fos.write(("clientApp.1.args=\n").getBytes());
- fos.write(("clientApp.1.main=net.i2p.router.Counter\n").getBytes());
- fos.write(("clientApp.1.name=counter\n").getBytes());
- fos.write(("clientApp.1.onBoot=true\n").getBytes());
- fos.write(("clientApp.2.args=i2ptunnel.config\n").getBytes());
- fos.write(("clientApp.2.main=net.i2p.i2ptunnel.TunnelControllerGroup\n").getBytes());
- fos.write(("clientApp.2.name=tunnels\n").getBytes());
- fos.write(("clientApp.2.delay=60\n").getBytes());
- fos.close();
- }
-
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
-
- private static void usage() {
- System.err.println("Usage: MultiRouterBuilder [routerDir routerPortStart]*");
- }
-}
diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java
index dd9ef576f..e1c767550 100644
--- a/router/java/src/net/i2p/router/RouterThrottleImpl.java
+++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java
@@ -27,6 +27,8 @@ class RouterThrottleImpl implements RouterThrottle {
private static final String PROP_MAX_TUNNELS = "router.maxParticipatingTunnels";
private static final int DEFAULT_MAX_TUNNELS = 5000;
private static final String PROP_MAX_PROCESSINGTIME = "router.defaultProcessingTimeThrottle";
+ private static final long DEFAULT_REJECT_STARTUP_TIME = 20*60*1000;
+ private static final String PROP_REJECT_STARTUP_TIME = "router.rejectStartupTime";
/**
* TO BE FIXED - SEE COMMENTS BELOW
@@ -39,13 +41,12 @@ class RouterThrottleImpl implements RouterThrottle {
/** = TrivialPreprocessor.PREPROCESSED_SIZE */
private static final int PREPROCESSED_SIZE = 1024;
- private static final long REJECT_STARTUP_TIME = 20*60*1000;
public RouterThrottleImpl(RouterContext context) {
_context = context;
_log = context.logManager().getLog(RouterThrottleImpl.class);
setTunnelStatus();
- _context.simpleScheduler().addEvent(new ResetStatus(), REJECT_STARTUP_TIME + 120*1000);
+ _context.simpleScheduler().addEvent(new ResetStatus(), 5*1000 + _context.getProperty(PROP_REJECT_STARTUP_TIME, DEFAULT_REJECT_STARTUP_TIME));
_context.statManager().createRateStat("router.throttleNetworkCause", "How lagged the jobQueue was when an I2NP was throttled", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
//_context.statManager().createRateStat("router.throttleNetDbCause", "How lagged the jobQueue was when a networkDb request was throttled", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
//_context.statManager().createRateStat("router.throttleTunnelCause", "How lagged the jobQueue was when a tunnel request was throttled", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
@@ -114,7 +115,7 @@ class RouterThrottleImpl implements RouterThrottle {
}
// Don't use CRIT because we don't want peers to think we're failing
- if (_context.router().getUptime() < REJECT_STARTUP_TIME) {
+ if (_context.router().getUptime() < DEFAULT_REJECT_STARTUP_TIME) {
setTunnelStatus(_x("Rejecting tunnels: Starting up"));
return TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
}