diff --git a/router/java/src/net/i2p/router/MultiRouter.java b/router/java/src/net/i2p/router/MultiRouter.java index 43f618bc2209725b75e6edd356fcff49cd6f2c6f..bee66b258950047a796f2abdd528977da0339e66 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)). <p /> * * <b>Usage:</b><pre> - * MultiRouter globalContextFile routerContextFile[ routerContextFile]* + * MultiRouter numberRouters * </pre> * * 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, <code>java -Di2p.encryption=off -jar lib/i2ptunnel.jar</code>).<p /> + * + * 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<Router> _routers = new ArrayList<Router>(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) { + private static void internalReseed() { + + HashSet<RouterInfo> riSet = new HashSet<RouterInfo>(); + 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(); - 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) {} + + 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 6a7c635bc8a3a5731387cf02cbc0edc9b9394bd3..0000000000000000000000000000000000000000 --- 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: <pre> - * MultiRouterBuilder [routerDir routerPortStart]* - * </pre> - * - * 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).<p /> - * - * It then builds a $routerDir/heartbeat.config containing the following lines:<ul> - * <li>i2cpHost=localhost</li> - * <li>i2cpPort=$routerPortStart+1</li> - * <li>numHops=2</li> - * <li>privateDestinationFile=$routerDir/heartbeat.keys</li> - * <li>publicDestinationFile=$routerDir/heartbeat.txt</li> - * </ul> - * - * Then it goes on to create the $routerDir/routerEnv.txt:<ul> - * <li>loggerFilenameOverride=$routerDir/logs/log-router-#.txt</li> - * <li>router.configLocation=$routerDir/router.config</li> - * <li>i2p.vmCommSystem=true</li> - * <li>i2p.encryption=off</li> - * </ul> - * - * In addition, it creates a baseEnv.txt: <ul> - * <li>loggerFilenameOverride=logs/log-base-#.txt</li> - * </ul> - * - * 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 dd9ef576fedfed6ebcd5af56ce91234ec488d40f..e1c76755070e4dbb40f3b562d8c9971574e8b9b6 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; }