propagate from branch 'i2p.i2p' (head 5d56a7eb371dddb9336e596bda69f99c91294b05)

to branch 'i2p.i2p.str4d.ui' (head 3aeafcdb5c0ffbc9c77f574558f8438d3e81133e)
This commit is contained in:
str4d
2017-04-09 06:52:22 +00:00
212 changed files with 6356 additions and 1526 deletions

View File

@@ -8,6 +8,7 @@ import net.i2p.stat.RateAverages;
import net.i2p.stat.RateStat;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
import net.i2p.util.SystemVersion;
/**
* Simple throttle that basically stops accepting messages or nontrivial
@@ -33,6 +34,8 @@ public class RouterThrottleImpl implements RouterThrottle {
private static final String PROP_MAX_PROCESSINGTIME = "router.defaultProcessingTimeThrottle";
private static final long DEFAULT_REJECT_STARTUP_TIME = 10*60*1000;
private static final String PROP_REJECT_STARTUP_TIME = "router.rejectStartupTime";
private static final int DEFAULT_MIN_THROTTLE_TUNNELS = SystemVersion.isAndroid() ? 100 :
SystemVersion.isARM() ? 500 : 1000;
/**
* TO BE FIXED - SEE COMMENTS BELOW
@@ -197,8 +200,15 @@ public class RouterThrottleImpl implements RouterThrottle {
return TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
}
// Throttle tunnels if min. throttle level is exceeded and default max participating tunnels (or fewer) is used.
if ((numTunnels > getMinThrottleTunnels()) && (DEFAULT_MAX_TUNNELS <= maxTunnels)) {
/*
* Throttle if we go above a minimum level of tunnels AND the maximum participating
* tunnels is default or lower.
*
* Lag based statistics use a moving average window (of for example 10 minutes), they are therefore
* sensitive to sudden rapid growth of load, which are not instantly detected by these metrics.
* Reduce tunnel growth if we are growing faster than the lag based metrics can detect reliably.
*/
if ((numTunnels > getMinThrottleTunnels()) && (DEFAULT_MAX_TUNNELS >= maxTunnels)) {
Rate avgTunnels = _context.statManager().getRate("tunnel.participatingTunnels").getRate(10*60*1000);
if (avgTunnels != null) {
double avg = avgTunnels.getAvgOrLifetimeAvg();
@@ -458,7 +468,7 @@ public class RouterThrottleImpl implements RouterThrottle {
/** dont ever probabalistically throttle tunnels if we have less than this many */
private int getMinThrottleTunnels() {
return _context.getProperty("router.minThrottleTunnels", 1000);
return _context.getProperty("router.minThrottleTunnels", DEFAULT_MIN_THROTTLE_TUNNELS);
}
private double getTunnelGrowthFactor() {

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 1;
public final static long BUILD = 15;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -65,10 +65,7 @@ public class TunnelPoolSettings {
public static final int DEFAULT_DURATION = 10*60*1000;
//public static final int DEFAULT_LENGTH = SystemVersion.isAndroid() ? 2 : 3;
private static final boolean isSlow = SystemVersion.isGNU() ||
SystemVersion.isARM() ||
SystemVersion.isApache() ||
!NativeBigInteger.isNative();
private static final boolean isSlow = SystemVersion.isSlow();
/** client only */
private static final int DEFAULT_IB_LENGTH = 3;

View File

@@ -108,19 +108,20 @@ public class Reseeder {
//
// https url:port, ending with "/" // certificates/reseed/ // certificates/ssl/ // notes
// ---------------------------------- ------------------------ ------------------------- ---------------
"https://randomrng.ddns.net/" + ',' + // randomrng_at_mail.i2p.crt // CA // Java 7+
"https://itoopie.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // Java 8+ only
"https://reseed.onion.im/" + ',' + // lazygravy_at_mail.i2p // reseed.onion.im.crt // Java 8+ only
"https://reseed.memcpy.io/" + ',' + // hottuna_at_mail.i2p.crt // CA // SNI required
"https://reseed.atomike.ninja/" + "," + // atomike_at_mail.i2p.crt // CA // SNI required, Java 8+ only
"https://reseed.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // SNI required, Java 8+ only
"https://i2p.manas.ca:8443/" + ',' + // zmx_at_mail.i2p.crt // CA // SNI required
"https://i2p-0.manas.ca:8443/" + ',' + // zmx_at_mail.i2p.crt // CA // SNI required
"https://reseed.i2p.vzaws.com:8443/" + ',' + // parg_at_mail.i2p.crt // reseed.i2p.vzaws.com.crt
"https://i2p.mooo.com/netDb/" + ',' + // bugme_at_mail.i2p.crt // i2p.mooo.com.crt
"https://download.xxlspeed.com/" + ',' + // backup_at_mail.i2p.crt // download.xxlspeed.com.crt // SNI required
"https://download.xxlspeed.com/" + ',' + // backup_at_mail.i2p.crt // CA // Java 8+
"https://netdb.i2p2.no/" + ',' + // meeh_at_mail.i2p.crt // netdb.i2p2.no.crt // SNI required
//"https://us.reseed.i2p2.no:444/" + ',' + // meeh_at_mail.i2p.crt // us.reseed.i2p2.no.crt
//"https://uk.reseed.i2p2.no:444/" + ',' + // meeh_at_mail.i2p.crt // uk.reseed.i2p2.no.crt
"https://reseed.i2p-projekt.de/"; // echelon_at_mail.i2p.crt // reseed.i2p-projekt.de.crt
"https://reseed.i2p-projekt.de/"; // echelon_at_mail.i2p.crt // echelon.reseed2017.crt // Java 8+
private static final String SU3_FILENAME = "i2pseeds.su3";

View File

@@ -55,7 +55,7 @@ public class CreateRouterInfoJob extends JobImpl {
public static final String KEYS2_FILENAME = "router.keys.dat";
static final String PROP_ROUTER_SIGTYPE = "router.sigType";
/** TODO make everybody Ed */
private static final SigType DEFAULT_SIGTYPE = (SystemVersion.isARM() || SystemVersion.isAndroid()) ?
private static final SigType DEFAULT_SIGTYPE = SystemVersion.isAndroid() ?
SigType.DSA_SHA1 : SigType.EdDSA_SHA512_Ed25519;
CreateRouterInfoJob(RouterContext ctx, Job next) {

View File

@@ -6,13 +6,25 @@ package net.i2p.router.startup;
*/
import java.io.File;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import net.i2p.data.DataHelper;
import net.i2p.router.RouterContext;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.SecureFileOutputStream;
import net.i2p.util.VersionComparator;
/**
* Migrate the clients.config and jetty.xml files
* from Jetty 5/6 to Jetty 7.
* from Jetty 5/6 to Jetty 7/8.
* Also migrate jetty.xml from Jetty 7/8 to Jetty 9.
*
* For each client for class org.mortbay.jetty.Server:
*<pre>
@@ -29,7 +41,8 @@ import net.i2p.router.RouterContext;
* Copies clients.config to clients.config.jetty6;
* Saves new clients.config.
*
* Does NOT preserve port number, thread counts, etc.
* Does NOT preserve port number, thread counts, etc. in the migration to 7/8.
* DOES preserve everything in the migration to 9.
*
* @since Jetty 6
*/
@@ -42,24 +55,43 @@ abstract class MigrateJetty {
private static final String NEW_CLASS = "net.i2p.jetty.JettyStart";
private static final String TEST_CLASS = "org.eclipse.jetty.server.Server";
private static final String BACKUP_SUFFIX = ".jetty6";
private static final String JETTY_TEMPLATE_DIR = "eepsite-jetty7";
private static final String BACKUP_SUFFIX_8 = ".jetty8";
private static final String JETTY_TEMPLATE_DIR = "eepsite-jetty9";
private static final String JETTY_TEMPLATE_PKGDIR = "eepsite";
private static final String BASE_CONTEXT = "contexts/base-context.xml";
private static final String CGI_CONTEXT = "contexts/cgi-context.xml";
private static final String PROP_JETTY9_MIGRATED = "router.startup.jetty9.migrated";
/**
* For each entry in apps, if the main class is an old Jetty class,
* migrate it to the new Jetty class, and update the Jetty config files.
*/
public static void migrate(RouterContext ctx, List<ClientAppConfig> apps) {
if (ctx.getBooleanProperty(PROP_JETTY9_MIGRATED))
return;
String installed = ctx.getProperty("router.firstVersion");
if (installed != null && VersionComparator.comp(installed, "0.9.30") >= 0) {
ctx.router().saveConfig(PROP_JETTY9_MIGRATED, "true");
return;
}
boolean shouldSave = false;
boolean jetty9success = false;
for (int i = 0; i < apps.size(); i++) {
ClientAppConfig app = apps.get(i);
if (!(app.className.equals(OLD_CLASS) || app.className.equals(OLD_CLASS_6)))
String client;
String backupSuffix;
if (app.className.equals(NEW_CLASS)) {
client = "client application " + i + " [" + app.clientName +
"] from Jetty 7/8 to Jetty 9";
backupSuffix = BACKUP_SUFFIX_8;
} else if (app.className.equals(OLD_CLASS) || app.className.equals(OLD_CLASS_6)) {
client = "client application " + i + " [" + app.clientName +
"] from Jetty 5/6 " + app.className +
" to Jetty 9 " + NEW_CLASS;
backupSuffix = BACKUP_SUFFIX;
} else {
continue;
String client = "client application " + i + " [" + app.clientName +
"] from Jetty 5/6 " + app.className +
" to Jetty 7 " + NEW_CLASS;
}
if (!hasLatestJetty()) {
System.err.println("WARNING: Jetty 7 unavailable, cannot migrate " + client);
continue;
@@ -80,12 +112,38 @@ abstract class MigrateJetty {
continue;
}
File eepsite = xmlFile.getParentFile();
boolean ok = backupFile(xmlFile);
boolean ok = backupFile(xmlFile, backupSuffix);
if (!ok) {
System.err.println("WARNING: Failed to backup up XML file " + xmlFile +
", cannot migrate " + client);
continue;
}
if (app.className.equals(NEW_CLASS)) {
// Do the migration of 8 to 9, handle additional command-line xml files too
for (int j = 0; j < args.length; j++) {
if (j > 0) {
// probably jetty-ssl.xml
xmlFile = new File(args[j]);
ok = backupFile(xmlFile, backupSuffix);
if (!ok) {
System.err.println("WARNING: Failed to backup up XML file " + xmlFile +
", cannot migrate " + client);
continue;
}
}
boolean ok9 = migrateToJetty9(xmlFile);
if (ok9) {
System.err.println("WARNING: Migrated " + client + ".\n" +
"Check the " + xmlFile.getName() + " file in " + eepsite + ".\n" +
"Your old " + xmlFile.getName() + " file was backed up to " + xmlFile.getAbsolutePath() + BACKUP_SUFFIX_8);
jetty9success = true;
}
}
continue;
}
// Below here is migration of 5/6 to 9
File baseEep = new File(ctx.getBaseDir(), JETTY_TEMPLATE_DIR);
// in packages, or perhaps on an uninstall/reinstall, the files are in eepsite/
if (!baseEep.exists())
@@ -141,12 +199,228 @@ abstract class MigrateJetty {
ClientAppConfig.writeClientAppConfig(ctx, apps);
System.err.println("WARNING: Migrated clients config file " + cfgFile +
" from Jetty 5/6 " + OLD_CLASS + '/' + OLD_CLASS_6 +
" to Jetty 7 " + NEW_CLASS);
" to Jetty 9 " + NEW_CLASS);
}
}
if (jetty9success)
ctx.router().saveConfig(PROP_JETTY9_MIGRATED, "true");
}
/**
* Migrate a jetty.xml file to Jetty 9.
* Unlike above, where we just migrate the new install file over for Jetty 9,
* here we modify the xml file in-place to preserve settings where possible.
*
* @return success
* @since Jetty 9
*/
private static boolean migrateToJetty9(File xmlFile) {
if (xmlFile.getName().equals("jetty-jmx.xml")) {
// This is lazy but nobody's using jmx, not worth the trouble
System.err.println("ERROR: Migration of " + xmlFile +
" file is not supported. Copy new file from $I2P/eepsite-jetty9/jetty-jmx.xml");
return false;
}
// we don't re-migrate from the template, we just add the
// necessary args for the QueuedThreadPool constructor in-place
// and fixup the renamed set call
boolean modified = false;
File eepsite = xmlFile.getParentFile();
File newFile = new File(eepsite, xmlFile.getName() + System.currentTimeMillis() + ".tmp");
FileInputStream in = null;
PrintWriter out = null;
try {
in = new FileInputStream(xmlFile);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(newFile), "UTF-8")));
String s;
boolean foundQTP = false;
boolean foundSTP = false;
boolean foundETP = false;
boolean foundSCC = false;
boolean foundHC = false;
boolean foundSSCC = false;
while ((s = DataHelper.readLine(in)) != null) {
// readLine() doesn't strip \r
if (s.endsWith("\r"))
s = s.substring(0, s.length() - 1);
if (s.contains("Modified by I2P migration script for Jetty 9.") ||
s.contains("This configuration supports Jetty 9.") ||
s.contains("http://www.eclipse.org/jetty/configure_9_0.dtd")) {
if (!modified)
break;
// else we've modified it twice?
} else if (s.contains("org.eclipse.jetty.util.thread.QueuedThreadPool")) {
foundQTP = true;
} else if (foundQTP) {
if (!(s.contains("Modified by") || s.contains("<Arg type=\"int\">"))) {
out.println(" <!-- Modified by I2P migration script for Jetty 9. Do not remove this line -->");
out.println(" <Arg type=\"int\">20</Arg> <!-- maxThreads, overridden below -->");
out.println(" <Arg type=\"int\">3</Arg> <!-- minThreads, overridden below -->");
out.println(" <Arg type=\"int\">60000</Arg> <!-- maxIdleTimeMs, overridden below -->");
modified = true;
}
foundQTP = false;
}
if (s.contains("<Set name=\"maxIdleTimeMs\">")) {
// <Set name="maxIdleTimeMs">60000</Set>
s = s.replace("<Set name=\"maxIdleTimeMs\">", "<Set name=\"idleTimeout\">");
modified = true;
} else if (s.contains("<Set name=\"ThreadPool\">")) {
// <Set name="ThreadPool">, must be changed to constructor arg
out.println(" <!-- Modified by I2P migration script for Jetty 9. Do not remove this line -->");
s = s.replace("<Set name=\"ThreadPool\">", "<Arg>");
foundSTP = true;
modified = true;
} else if (foundSTP && !foundETP && s.contains("</Set>") && !s.contains("<Set")) {
// </Set> (close of <Set name="ThreadPool">)
// All the lines above have <Set>...</Set> on the same line, if they don't, this will break.
s = s.replace("</Set>", "</Arg>");
foundETP = true;
} else if (s.contains("org.eclipse.jetty.server.nio.SelectChannelConnector")) {
s = s.replace("org.eclipse.jetty.server.nio.SelectChannelConnector", "org.eclipse.jetty.server.ServerConnector");
out.println(" <!-- Modified by I2P migration script for Jetty 9. Do not remove this line -->");
out.println(s);
out.println(" <Arg><Ref id=\"Server\" /></Arg>");
out.println(" <Arg type=\"int\">1</Arg> <!-- number of acceptors -->");
out.println(" <Arg type=\"int\">0</Arg> <!-- default number of selectors -->");
out.println(" <Arg>");
out.println(" <Array type=\"org.eclipse.jetty.server.ConnectionFactory\"> <!-- varargs so we need an array -->");
out.println(" <Item>");
out.println(" <New class=\"org.eclipse.jetty.server.HttpConnectionFactory\">");
out.println(" <Arg>");
out.println(" <New class=\"org.eclipse.jetty.server.HttpConfiguration\">");
out.println(" <Set name=\"sendServerVersion\">false</Set>");
out.println(" <Set name=\"sendDateHeader\">true</Set>");
out.println(" </New>");
out.println(" </Arg>");
out.println(" </New>");
out.println(" </Item>");
out.println(" </Array>");
out.println(" </Arg>");
modified = true;
continue;
// SSL starts here
} else if (s.contains("org.eclipse.jetty.http.ssl.SslContextFactory")) {
s = s.replace("org.eclipse.jetty.http.ssl.SslContextFactory", "org.eclipse.jetty.util.ssl.SslContextFactory");
out.println(" <!-- Modified by I2P migration script for Jetty 9. Do not remove this line -->");
out.println(s);
// don't try to migrate from below, just generate a new list
out.println(" <Set name=\"ExcludeCipherSuites\">");
out.println(" <Array type=\"java.lang.String\">");
for (String ss : I2PSSLSocketFactory.EXCLUDE_CIPHERS) {
out.println(" <Item>" + ss + "</Item>");
}
out.println(" </Array>");
out.println(" </Set>");
out.println(" <Set name=\"ExcludeProtocols\">");
out.println(" <Array type=\"java.lang.String\">");
for (String ss : I2PSSLSocketFactory.EXCLUDE_PROTOCOLS) {
out.println(" <Item>" + ss + "</Item>");
}
out.println(" </Array>");
out.println(" </Set>");
modified = true;
continue;
} else if (s.contains("org.eclipse.jetty.server.ssl.SslSelectChannelConnector")) {
s = s.replace("org.eclipse.jetty.server.ssl.SslSelectChannelConnector", "org.eclipse.jetty.server.ServerConnector");
out.println(" <!-- Modified by I2P migration script for Jetty 9. Do not remove this line -->");
out.println(s);
out.println(" <Arg><Ref id=\"Server\" /></Arg>");
out.println(" <Arg type=\"int\">1</Arg> <!-- number of acceptors -->");
out.println(" <Arg type=\"int\">0</Arg> <!-- default number of selectors -->");
out.println(" <Arg>");
out.println(" <Array type=\"org.eclipse.jetty.server.ConnectionFactory\"> <!-- varargs so we need an array -->");
out.println(" <Item>");
out.println(" <New class=\"org.eclipse.jetty.server.SslConnectionFactory\">");
out.println(" <Arg><Ref id=\"sslContextFactory\" /></Arg>");
out.println(" <Arg>http/1.1</Arg>");
out.println(" </New>");
out.println(" </Item>");
out.println(" <Item>");
out.println(" <New class=\"org.eclipse.jetty.server.HttpConnectionFactory\">");
out.println(" <Arg>");
out.println(" <New class=\"org.eclipse.jetty.server.HttpConfiguration\">");
out.println(" <Set name=\"sendServerVersion\">false</Set>");
out.println(" <Set name=\"sendDateHeader\">true</Set>");
out.println(" </New>");
out.println(" </Arg>");
out.println(" </New>");
out.println(" </Item>");
out.println(" </Array>");
out.println(" </Arg>");
foundSSCC = true;
modified = true;
continue;
} else if (foundSSCC && s.contains("<Set name=\"ExcludeCipherSuites\">")) {
// delete the old ExcludeCipherSuites in this section
do {
s = DataHelper.readLine(in);
} while(s != null && !s.contains("</Set>"));
modified = true;
continue;
} else if (foundSSCC &&
s.contains("<Ref id=\"sslContextFactory\"")) {
// delete old one in this section, replaced above
modified = true;
continue;
} else if (s.contains("<Set name=\"KeyStore\">")) {
s = s.replace("<Set name=\"KeyStore\">", "<Set name=\"KeyStorePath\">");
modified = true;
} else if (s.contains("<Set name=\"TrustStore\">")) {
s = s.replace("<Set name=\"TrustStore\">", "<Set name=\"TrustStorePath\">");
modified = true;
// SSL ends here
} else if (s.contains("class=\"org.eclipse.jetty.deploy.providers.ContextProvider\">")) {
// WebAppProvider now also does what ContextProvider used to do
out.println(" <!-- Modified by I2P migration script for Jetty 9. Do not remove this line -->");
s = s.replace("class=\"org.eclipse.jetty.deploy.providers.ContextProvider\">", "class=\"org.eclipse.jetty.deploy.providers.WebAppProvider\">");
modified = true;
} else if (s.contains("<Set name=\"maxIdleTime\">")) {
s = s.replace("<Set name=\"maxIdleTime\">", "<Set name=\"idleTimeout\">");
modified = true;
} else if (s.contains("<Set name=\"gracefulShutdown\">")) {
s = s.replace("<Set name=\"gracefulShutdown\">", "<Set name=\"stopTimeout\">");
modified = true;
} else if (s.contains("org.eclipse.jetty.server.HttpConfiguration")) {
foundHC = true;
} else if (!foundHC &&
(s.contains("<Set name=\"sendServerVersion\">") ||
s.contains("<Set name=\"sendDateHeader\">"))) {
// old ones for Server, not in HTTPConfiguration section, delete
modified = true;
continue;
} else if (s.contains("<Set name=\"Acceptors\">") ||
s.contains("<Set name=\"acceptors\">") ||
s.contains("<Set name=\"statsOn\">") ||
s.contains("<Set name=\"confidentialPort\">") ||
s.contains("<Set name=\"lowResourcesConnections\">") ||
s.contains("<Set name=\"lowResourcesMaxIdleTime\">") ||
s.contains("<Set name=\"useDirectBuffers\">")) {
// delete
modified = true;
continue;
}
out.println(s);
}
} catch (IOException ioe) {
if (in != null) {
System.err.println("FAILED migration of " + xmlFile + ": " + ioe);
}
return false;
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
if (out != null) out.close();
}
if (modified) {
return FileUtil.rename(newFile, xmlFile);
} else {
newFile.delete();
return true;
}
}
/** do we have Jetty 7? */
/** do we have Jetty 7/8/9? */
private static boolean hasLatestJetty() {
if (!_wasChecked) {
try {
@@ -164,9 +438,18 @@ abstract class MigrateJetty {
* @since Jetty 7
*/
private static boolean backupFile(File from) {
return backupFile(from, BACKUP_SUFFIX);
}
/**
* Backup a file with given suffix
* @return success
* @since Jetty 9
*/
private static boolean backupFile(File from, String suffix) {
if (!from.exists())
return true;
File to = new File(from.getAbsolutePath() + BACKUP_SUFFIX);
File to = new File(from.getAbsolutePath() + suffix);
if (to.exists())
to = new File(to.getAbsolutePath() + "." + System.currentTimeMillis());
boolean rv = WorkingDir.copyFile(from, to);

View File

@@ -22,21 +22,19 @@ import net.i2p.util.Log;
*
* @since 0.9.4
*/
public class RouterAppManager implements ClientAppManager {
public class RouterAppManager extends ClientAppManagerImpl {
private final RouterContext _context;
private final Log _log;
// client to args
// this assumes clients do not override equals()
private final ConcurrentHashMap<ClientApp, String[]> _clients;
// registered name to client
private final ConcurrentHashMap<String, ClientApp> _registered;
public RouterAppManager(RouterContext ctx) {
super(ctx);
_context = ctx;
_log = ctx.logManager().getLog(RouterAppManager.class);
_clients = new ConcurrentHashMap<ClientApp, String[]>(16);
_registered = new ConcurrentHashMap<String, ClientApp>(8);
ctx.addShutdownTask(new Shutdown());
}
@@ -48,7 +46,7 @@ public class RouterAppManager implements ClientAppManager {
public boolean addAndStart(ClientApp app, String[] args) {
if (_log.shouldLog(Log.INFO))
_log.info("Client " + app.getDisplayName() + " ADDED");
String[] old = _clients.put(app, args);
String[] old = _clients.putIfAbsent(app, args);
if (old != null)
throw new IllegalArgumentException("already added");
try {
@@ -91,6 +89,7 @@ public class RouterAppManager implements ClientAppManager {
* @param message may be null
* @param e may be null
*/
@Override
public void notify(ClientApp app, ClientAppState state, String message, Exception e) {
switch(state) {
case UNINITIALIZED:
@@ -137,6 +136,7 @@ public class RouterAppManager implements ClientAppManager {
* @param app non-null
* @return true if successful, false if duplicate name
*/
@Override
public boolean register(ClientApp app) {
if (!_clients.containsKey(app)) {
// Allow registration even if we didn't start it,
@@ -148,32 +148,9 @@ public class RouterAppManager implements ClientAppManager {
if (_log.shouldLog(Log.INFO))
_log.info("Client " + app.getDisplayName() + " REGISTERED AS " + app.getName());
// TODO if old app in there is not running and != this app, allow replacement
return _registered.putIfAbsent(app.getName(), app) == null;
return super.register(app);
}
/**
* Unregister with the manager. Name must be the same as that from register().
* Only required for apps used by other apps.
*
* @param app non-null
*/
public void unregister(ClientApp app) {
_registered.remove(app.getName(), app);
}
/**
* Get a registered app.
* Only used for apps finding other apps.
* Do not hold a static reference.
* If you only need to find a port, use the PortMapper instead.
*
* @param name non-null
* @return client app or null
*/
public ClientApp getRegisteredApp(String name) {
return _registered.get(name);
}
/// end ClientAppManager interface
/**

View File

@@ -73,6 +73,7 @@ public class WorkingDir {
boolean isWindows = SystemVersion.isWindows();
File dirf = null;
String gentooWarning = null;
if (dir != null) {
dirf = new SecureDirectory(dir);
} else {
@@ -92,10 +93,46 @@ public class WorkingDir {
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_MAC);
}
} else {
if (SystemVersion.isLinuxService())
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_DAEMON);
else
if (SystemVersion.isLinuxService()) {
if (SystemVersion.isGentoo() &&
SystemVersion.GENTOO_USER.equals(System.getProperty("user.name"))) {
// whoops, we didn't recognize Gentoo as a service until 0.9.29,
// so the config dir was /var/lib/i2p/.i2p through 0.9.28
// and changed to /var/lib/i2p/i2p-config in 0.9.29.
// Look for both to decide which to use.
// We prefer .i2p if neither exists.
// We prefer the newer if both exist.
File d1 = new SecureDirectory(home, WORKING_DIR_DEFAULT);
File d2 = new SecureDirectory(home, WORKING_DIR_DEFAULT_DAEMON);
boolean e1 = isSetup(d1);
boolean e2 = isSetup(d2);
if (e1 && e2) {
// d1 is probably older. Switch if it isn't.
if (d2.lastModified() < d1.lastModified()) {
File tmp = d2;
d2 = d1;
d1 = tmp;
// d1 now is the older one
}
dirf = d2;
gentooWarning = "Warning - Found both an old configuration directory " + d1.getAbsolutePath() +
" and new configuration directory " + d2.getAbsolutePath() +
" created due to a bug in release 0.9.29\n. Using the new configuration" +
" directory. To use the old directory instead, stop i2p," +
" delete the new directory, and restart.";
} else if (e1 && !e2) {
dirf = d1;
} else if (!e1 && e2) {
dirf = d2;
} else {
dirf = d1;
}
} else {
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_DAEMON);
}
} else {
dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT);
}
}
}
@@ -134,6 +171,9 @@ public class WorkingDir {
if (dirf.isDirectory()) {
if (isSetup(dirf)) {
setupSystemOut(rv);
// see above for why
if (gentooWarning != null)
System.err.println(gentooWarning);
return rv; // all is good, we found the user directory
}
}
@@ -327,7 +367,6 @@ public class WorkingDir {
} catch (IOException ioe) {
if (in != null) {
System.err.println("FAILED copy " + oldFile + ": " + ioe);
return false;
}
return false;
} finally {
@@ -365,7 +404,6 @@ public class WorkingDir {
} catch (IOException ioe) {
if (in != null) {
System.err.println("FAILED copy " + oldFile + ": " + ioe);
return false;
}
return false;
} finally {

View File

@@ -53,7 +53,10 @@ public class OOMListener implements I2PThread.OOMEventListener {
// you the actual config file path, have to guess
String path;
if (SystemVersion.isLinuxService()) {
path = "/etc/i2p";
if (SystemVersion.isGentoo())
path = "/usr/share/i2p";
else
path = "/etc/i2p";
} else {
path = _context.getBaseDir().toString();
}

View File

@@ -815,18 +815,18 @@ public abstract class TransportImpl implements Transport {
/**
* This returns true if the force-firewalled setting is configured, false otherwise.
*
* @since 0.9.20
* @since 0.9.20, public since 0.9.30
*/
protected boolean isIPv4Firewalled() {
public boolean isIPv4Firewalled() {
return TransportUtil.isIPv4Firewalled(_context, getStyle());
}
/**
* This returns true if the force-firewalled setting is configured, false otherwise.
*
* @since 0.9.27
* @since 0.9.27, public since 0.9.30
*/
protected boolean isIPv6Firewalled() {
public boolean isIPv6Firewalled() {
return TransportUtil.isIPv6Firewalled(_context, getStyle());
}
@@ -987,9 +987,9 @@ public abstract class TransportImpl implements Transport {
}
/**
* @since IPv6
* @since IPv6, public since 0.9.30
*/
protected TransportUtil.IPv6Config getIPv6Config() {
public TransportUtil.IPv6Config getIPv6Config() {
return TransportUtil.getIPv6Config(_context, getStyle());
}

View File

@@ -170,7 +170,7 @@ class IntroductionManager {
* @return number of introducers added
*/
public int pickInbound(Properties ssuOptions, int howMany) {
int start = _context.random().nextInt(Integer.MAX_VALUE);
int start = _context.random().nextInt();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Picking inbound out of " + _inbound.size());
if (_inbound.isEmpty()) return 0;

View File

@@ -1215,17 +1215,20 @@ class PacketBuilder {
UDPAddress addr = state.getRemoteAddress();
int count = addr.getIntroducerCount();
List<UDPPacket> rv = new ArrayList<UDPPacket>(count);
long cutoff = _context.clock().now() + 5*60*1000L;
for (int i = 0; i < count; i++) {
InetAddress iaddr = addr.getIntroducerHost(i);
int iport = addr.getIntroducerPort(i);
byte ikey[] = addr.getIntroducerKey(i);
long tag = addr.getIntroducerTag(i);
long exp = addr.getIntroducerExpiration(i);
// let's not use an introducer on a privileged port, sounds like trouble
if (ikey == null || !TransportUtil.isValidPort(iport) ||
iaddr == null || tag <= 0 ||
// must be IPv4 for now as we don't send Alice IP/port, see below
iaddr.getAddress().length != 4 ||
(!_transport.isValid(iaddr.getAddress())) ||
(exp > 0 && exp < cutoff) ||
(Arrays.equals(iaddr.getAddress(), _transport.getExternalIP()) && !_transport.allowLocal())) {
if (_log.shouldLog(Log.WARN))
_log.warn("Cannot build a relay request to " + state.getRemoteIdentity().calculateHash()

View File

@@ -0,0 +1,146 @@
package net.i2p.router.transport.udp;
import java.util.concurrent.atomic.AtomicLong;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
import static net.i2p.router.transport.TransportUtil.IPv6Config.*;
import static net.i2p.router.transport.udp.PeerTestState.Role.*;
/**
* Initiate a test (we are Alice)
*
* @since 0.9.30 moved out of UDPTransport
*/
class PeerTestEvent extends SimpleTimer2.TimedEvent {
private final RouterContext _context;
private final Log _log;
private final UDPTransport _transport;
private final PeerTestManager _testManager;
private boolean _alive;
/** when did we last test our reachability */
private final AtomicLong _lastTested = new AtomicLong();
private final AtomicLong _lastTestedV6 = new AtomicLong();
private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2;
private int _forceRun;
private static final int TEST_FREQUENCY = 13*60*1000;
private static final int MIN_TEST_FREQUENCY = 45*1000;
PeerTestEvent(RouterContext ctx, UDPTransport udp, PeerTestManager ptmgr) {
super(ctx.simpleTimer2());
_context = ctx;
_log = ctx.logManager().getLog(PeerTestEvent.class);
_transport = udp;
_testManager = ptmgr;
}
public synchronized void timeReached() {
// just for IPv6 for now
if (shouldTest()) {
long now = _context.clock().now();
long sinceRunV4 = now - _lastTested.get();
long sinceRunV6 = now - _lastTestedV6.get();
if (_forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) {
locked_runTest(false);
} else if (_transport.hasIPv6Address() &&_forceRun == FORCE_IPV6 && sinceRunV6 >= MIN_TEST_FREQUENCY) {
locked_runTest(true);
} else if (sinceRunV4 >= TEST_FREQUENCY && _transport.getIPv6Config() != IPV6_ONLY) {
locked_runTest(false);
} else if (_transport.hasIPv6Address() && sinceRunV6 >= TEST_FREQUENCY) {
locked_runTest(true);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("PTE timeReached(), no test run, last v4 test: " + new java.util.Date(_lastTested.get()) +
" last v6 test: " + new java.util.Date(_lastTestedV6.get()));
}
}
if (_alive) {
long delay = (TEST_FREQUENCY / 2) + _context.random().nextInt(TEST_FREQUENCY);
// if we have 2 addresses, give IPv6 a chance also
if (_transport.hasIPv6Address() && _transport.getIPv6Config() != IPV6_ONLY)
delay /= 2;
schedule(delay);
}
}
private void locked_runTest(boolean isIPv6) {
PeerState bob = _transport.pickTestPeer(BOB, isIPv6, null);
if (bob != null) {
if (_log.shouldLog(Log.INFO))
_log.info("Running periodic test with bob = " + bob);
_testManager.runTest(bob.getRemoteIPAddress(), bob.getRemotePort(), bob.getCurrentCipherKey(), bob.getCurrentMACKey());
setLastTested(isIPv6);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to run peer test, no peers available - v6? " + isIPv6);
}
_forceRun = NO_FORCE;
}
/**
* Run within the next 45 seconds at the latest
* @since 0.9.13
*/
public synchronized void forceRunSoon(boolean isIPv6) {
if (!isIPv6 && _transport.isIPv4Firewalled())
return;
if (isIPv6 && _transport.isIPv6Firewalled())
return;
_forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4;
reschedule(MIN_TEST_FREQUENCY);
}
/**
*
* Run within the next 5 seconds at the latest
* @since 0.9.13
*/
public synchronized void forceRunImmediately(boolean isIPv6) {
if (!isIPv6 && _transport.isIPv4Firewalled())
return;
if (isIPv6 && _transport.isIPv6Firewalled())
return;
if (isIPv6)
_lastTestedV6.set(0);
else
_lastTested.set(0);
_forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4;
reschedule(5*1000);
}
public synchronized void setIsAlive(boolean isAlive) {
_alive = isAlive;
if (isAlive) {
long delay = _context.random().nextInt(2*TEST_FREQUENCY);
reschedule(delay);
} else {
cancel();
}
}
/**
* Set the last-tested timer to now
* @since 0.9.13
*/
public void setLastTested(boolean isIPv6) {
// do not synchronize - deadlock with PeerTestManager
long now = _context.clock().now();
if (isIPv6)
_lastTestedV6.set(now);
else
_lastTested.set(now);
if (_log.shouldLog(Log.DEBUG))
_log.debug("PTE.setLastTested() - v6? " + isIPv6, new Exception());
}
private boolean shouldTest() {
return ! (_context.router().isHidden() ||
(_transport.isIPv4Firewalled() && _transport.isIPv6Firewalled()));
//String val = _context.getProperty(PROP_SHOULD_TEST);
//return ( (val != null) && ("true".equals(val)) );
}
}

View File

@@ -75,12 +75,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private volatile PacketPusher _pusher;
private final InboundMessageFragments _inboundFragments;
//private UDPFlooder _flooder;
private PeerTestManager _testManager;
private final PeerTestManager _testManager;
private final IntroductionManager _introManager;
private final ExpirePeerEvent _expireEvent;
private final PeerTestEvent _testEvent;
private final PacketBuilder _destroyBuilder;
private Status _reachabilityStatus;
private Status _reachabilityStatusPending;
// only for logging, to be removed
private long _reachabilityStatusLastUpdated;
private int _reachabilityStatusUnchanged;
private long _introducersSelectedOn;
@@ -195,14 +197,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private static final int MAX_CONSECUTIVE_FAILED = 5;
public static final int DEFAULT_COST = 5;
private static final int TEST_FREQUENCY = 13*60*1000;
private static final int MIN_TEST_FREQUENCY = 45*1000;
static final long[] RATES = { 10*60*1000 };
/** minimum active peers to maintain IP detection, etc. */
private static final int MIN_PEERS = 5;
private static final int MIN_PEERS_IF_HAVE_V6 = 30;
/** minimum peers volunteering to be introducers if we need that */
private static final int MIN_INTRODUCER_POOL = 5;
private static final long INTRODUCER_EXPIRATION_MARGIN = 20*60*1000L;
private static final int[] BID_VALUES = { 15, 20, 50, 65, 80, 95, 100, 115, TransportBid.TRANSIENT_FAIL };
private static final int FAST_PREFERRED_BID = 0;
@@ -265,8 +266,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// _flooder = new UDPFlooder(_context, this);
_expireTimeout = EXPIRE_TIMEOUT;
_expireEvent = new ExpirePeerEvent();
_testEvent = new PeerTestEvent();
_testManager = new PeerTestManager(_context, this);
_testEvent = new PeerTestEvent(_context, this, _testManager);
_reachabilityStatus = Status.UNKNOWN;
_reachabilityStatusPending = Status.OK;
_introManager = new IntroductionManager(_context, this);
_introducersSelectedOn = -1;
_lastInboundReceivedOn = -1;
@@ -475,9 +478,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
if (_establisher == null)
_establisher = new EstablishmentManager(_context, this);
if (_testManager == null)
_testManager = new PeerTestManager(_context, this);
if (_handler == null)
_handler = new PacketHandler(_context, this, _establisher, _inboundFragments, _testManager, _introManager);
@@ -666,6 +666,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return null;
}
/**
* For PeerTestManager
* @since 0.9.30
*/
boolean hasIPv6Address() {
return _haveIPv6Address;
}
/**
* Is this IP too close to ours to trust it for
* things like relaying?
@@ -1340,8 +1348,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
status != Status.IPV4_DISABLED_IPV6_FIREWALLED &&
status != Status.DISCONNECTED &&
_reachabilityStatusUnchanged < 7) {
// IPv4 only for now
_testEvent.forceRunSoon(false);
_testEvent.forceRunSoon(peer.isIPv6());
}
}
return true;
@@ -1558,17 +1565,21 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
RouterAddress addr = getCurrentAddress(false);
if (introducersRequired()) {
UDPAddress ua = new UDPAddress(addr);
long now = _context.clock().now();
int valid = 0;
for (int i = 0; i < ua.getIntroducerCount(); i++) {
// warning: this is only valid as long as we use the ident hash as their key.
byte[] key = ua.getIntroducerKey(i);
if (key.length != Hash.HASH_LENGTH)
continue;
long exp = ua.getIntroducerExpiration(i);
if (exp > 0 && exp < now + INTRODUCER_EXPIRATION_MARGIN)
continue;
PeerState peer = getPeerState(new Hash(key));
if (peer != null)
valid++;
}
long sinceSelected = _context.clock().now() - _introducersSelectedOn;
long sinceSelected = now - _introducersSelectedOn;
if (valid >= PUBLIC_RELAY_COUNT) {
// try to shift 'em around every 10 minutes or so
if (sinceSelected > 17*60*1000) {
@@ -3146,6 +3157,27 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
if (status != old) {
// for the following transitions ONLY, require two in a row
// to prevent thrashing
if ((old == Status.OK && (status == Status.DIFFERENT ||
status == Status.REJECT_UNSOLICITED ||
status == Status.IPV4_FIREWALLED_IPV6_OK ||
status == Status.IPV4_SNAT_IPV6_OK ||
status == Status.IPV4_OK_IPV6_FIREWALLED)) ||
(status == Status.OK && (old == Status.DIFFERENT ||
old == Status.REJECT_UNSOLICITED ||
old == Status.IPV4_FIREWALLED_IPV6_OK ||
old == Status.IPV4_SNAT_IPV6_OK ||
old == Status.IPV4_OK_IPV6_FIREWALLED))) {
if (status != _reachabilityStatusPending) {
if (_log.shouldLog(Log.WARN))
_log.warn("Old status: " + old + " status pending confirmation: " + status +
" Caused by update: " + newStatus);
_reachabilityStatusPending = status;
_testEvent.forceRunSoon(isIPv6);
return;
}
}
_reachabilityStatusUnchanged = 0;
long now = _context.clock().now();
_reachabilityStatusLastUpdated = now;
@@ -3153,6 +3185,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} else {
_reachabilityStatusUnchanged++;
}
_reachabilityStatusPending = status;
}
if (status != old) {
if (_log.shouldLog(Log.WARN))
@@ -3278,129 +3311,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return null;
}
private boolean shouldTest() {
return ! (_context.router().isHidden() ||
(isIPv4Firewalled() && isIPv6Firewalled()));
//String val = _context.getProperty(PROP_SHOULD_TEST);
//return ( (val != null) && ("true".equals(val)) );
}
/**
* Initiate a test (we are Alice)
*/
private class PeerTestEvent extends SimpleTimer2.TimedEvent {
private boolean _alive;
/** when did we last test our reachability */
private final AtomicLong _lastTested = new AtomicLong();
private final AtomicLong _lastTestedV6 = new AtomicLong();
private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2;
private int _forceRun;
PeerTestEvent() {
super(_context.simpleTimer2());
}
public synchronized void timeReached() {
// just for IPv6 for now
if (shouldTest()) {
long now = _context.clock().now();
long sinceRunV4 = now - _lastTested.get();
long sinceRunV6 = now - _lastTestedV6.get();
if (_forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) {
locked_runTest(false);
} else if (_haveIPv6Address &&_forceRun == FORCE_IPV6 && sinceRunV6 >= MIN_TEST_FREQUENCY) {
locked_runTest(true);
} else if (sinceRunV4 >= TEST_FREQUENCY && getIPv6Config() != IPV6_ONLY) {
locked_runTest(false);
} else if (_haveIPv6Address && sinceRunV6 >= TEST_FREQUENCY) {
locked_runTest(true);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("PTE timeReached(), no test run, last v4 test: " + new java.util.Date(_lastTested.get()) +
" last v6 test: " + new java.util.Date(_lastTestedV6.get()));
}
}
if (_alive) {
long delay = (TEST_FREQUENCY / 2) + _context.random().nextInt(TEST_FREQUENCY);
// if we have 2 addresses, give IPv6 a chance also
if (_haveIPv6Address && getIPv6Config() != IPV6_ONLY)
delay /= 2;
schedule(delay);
}
}
private void locked_runTest(boolean isIPv6) {
PeerState bob = pickTestPeer(BOB, isIPv6, null);
if (bob != null) {
if (_log.shouldLog(Log.INFO))
_log.info("Running periodic test with bob = " + bob);
_testManager.runTest(bob.getRemoteIPAddress(), bob.getRemotePort(), bob.getCurrentCipherKey(), bob.getCurrentMACKey());
setLastTested(isIPv6);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to run peer test, no peers available - v6? " + isIPv6);
}
_forceRun = NO_FORCE;
}
/**
* Run within the next 45 seconds at the latest
* @since 0.9.13
*/
public synchronized void forceRunSoon(boolean isIPv6) {
if (!isIPv6 && isIPv4Firewalled())
return;
if (isIPv6 && isIPv6Firewalled())
return;
_forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4;
reschedule(MIN_TEST_FREQUENCY);
}
/**
*
* Run within the next 5 seconds at the latest
* @since 0.9.13
*/
public synchronized void forceRunImmediately(boolean isIPv6) {
if (!isIPv6 && isIPv4Firewalled())
return;
if (isIPv6 && isIPv6Firewalled())
return;
if (isIPv6)
_lastTestedV6.set(0);
else
_lastTested.set(0);
_forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4;
reschedule(5*1000);
}
public synchronized void setIsAlive(boolean isAlive) {
_alive = isAlive;
if (isAlive) {
long delay = _context.random().nextInt(2*TEST_FREQUENCY);
reschedule(delay);
} else {
cancel();
}
}
/**
* Set the last-tested timer to now
* @since 0.9.13
*/
public void setLastTested(boolean isIPv6) {
// do not synchronize - deadlock with PeerTestManager
long now = _context.clock().now();
if (isIPv6)
_lastTestedV6.set(now);
else
_lastTested.set(now);
if (_log.shouldLog(Log.DEBUG))
_log.debug("PTE.setLastTested() - v6? " + isIPv6, new Exception());
}
}
/**
* Periodically ping the introducers, split out since we need to
* do it faster than we rebuild our address.

View File

@@ -439,7 +439,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
/**
* Add another destination to the same tunnels.
* Must have same encryption key an a different signing key.
* Must have same encryption key and a different signing key.
* @throws IllegalArgumentException if not
* @return success
* @since 0.9.21