merge of '44418e8f7048de3ac06833176b607d55afc94bdd'

and '6cd2f8bb60720e3aeeb500d67b3f162f2831c3fa'
This commit is contained in:
z3d
2010-04-05 12:26:28 +00:00
30 changed files with 423 additions and 107 deletions

View File

@@ -39,6 +39,7 @@ import net.i2p.I2PAppContext;
public class Daemon {
public static final String VERSION = "2.0.3";
private static final Daemon _instance = new Daemon();
private boolean _running;
/**
* Update the router and published address books using remote data from the
@@ -126,6 +127,7 @@ public class Daemon {
}
public void run(String[] args) {
_running = true;
String settingsLocation = "config.txt";
File homeFile;
if (args.length > 0) {
@@ -166,7 +168,7 @@ public class Daemon {
// Static method, and redundent Thread.currentThread().sleep(5*60*1000);
} catch (InterruptedException ie) {}
while (true) {
while (_running) {
long delay = Long.parseLong((String) settings.get("update_delay"));
if (delay < 1) {
delay = 1;
@@ -179,6 +181,8 @@ public class Daemon {
}
} catch (InterruptedException exp) {
}
if (!_running)
break;
settings = ConfigParser.parse(settingsFile, defaultSettings);
}
}
@@ -192,4 +196,9 @@ public class Daemon {
_instance.notifyAll();
}
}
public static void stop() {
_instance._running = false;
wakeup();
}
}

View File

@@ -51,4 +51,9 @@ public class DaemonThread extends Thread {
//}
Daemon.main(this.args);
}
}
public void halt() {
Daemon.stop();
interrupt();
}
}

View File

@@ -41,7 +41,7 @@ import javax.servlet.http.HttpServletResponse;
*
*/
public class Servlet extends HttpServlet {
private Thread thread;
private DaemonThread thread;
private String nonce;
private static final String PROP_NONCE = "addressbook.nonce";
@@ -88,4 +88,9 @@ public class Servlet extends HttpServlet {
//System.out.println("INFO: config root under " + args[0]);
}
@Override
public void destroy() {
this.thread.halt();
super.destroy();
}
}

View File

@@ -40,6 +40,8 @@ public class SnarkManager implements Snark.CompleteListener {
private I2PSnarkUtil _util;
private PeerCoordinatorSet _peerCoordinatorSet;
private ConnectionAcceptor _connectionAcceptor;
private Thread _monitor;
private boolean _running;
public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
@@ -78,15 +80,22 @@ public class SnarkManager implements Snark.CompleteListener {
* for i2cp host/port or i2psnark.dir
*/
public void start() {
_running = true;
_peerCoordinatorSet = new PeerCoordinatorSet();
_connectionAcceptor = new ConnectionAcceptor(_util);
int minutes = getStartupDelayMinutes();
_messages.add(_("Adding torrents in {0} minutes", minutes));
I2PAppThread monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor");
monitor.setDaemon(true);
monitor.start();
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
_monitor.start();
_context.addShutdownTask(new SnarkManagerShutdown());
}
public void stop() {
_running = false;
_monitor.interrupt();
_connectionAcceptor.halt();
(new SnarkManagerShutdown()).run();
}
/** hook to I2PSnarkUtil for the servlet */
public I2PSnarkUtil util() { return _util; }

View File

@@ -150,7 +150,7 @@ public class TrackerClient extends I2PAppThread
continue;
String dest = _util.lookup(url.substring(7, slash));
if (dest == null) {
_log.error("Announce host unknown: [" + url + "]");
_log.error("Announce host unknown: [" + url.substring(7, slash) + "]");
continue;
}
if (primary.startsWith("http://" + dest))
@@ -258,7 +258,7 @@ public class TrackerClient extends I2PAppThread
tr.started = true;
Set peers = info.getPeers();
tr.seenPeers = peers.size();
tr.seenPeers = info.getPeerCount();
if (coordinator.trackerSeenPeers < tr.seenPeers) // update rising number quickly
coordinator.trackerSeenPeers = tr.seenPeers;
if ( (left > 0) && (!completed) ) {
@@ -269,6 +269,7 @@ public class TrackerClient extends I2PAppThread
Iterator it = ordered.iterator();
while (it.hasNext()) {
Peer cur = (Peer)it.next();
// FIXME if id == us || dest == us continue;
// only delay if we actually make an attempt to add peer
if(coordinator.addPeer(cur)) {
int delay = DELAY_MUL;
@@ -356,6 +357,10 @@ public class TrackerClient extends I2PAppThread
+ "&downloaded=" + downloaded
+ "&left=" + left
+ ((! event.equals(NO_EVENT)) ? ("&event=" + event) : "");
if (left <= 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
s += "&numwant=0";
else
s += "&numwant=" + _util.getMaxConnections();
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
tr.lastRequestTime = System.currentTimeMillis();
@@ -430,7 +435,7 @@ public class TrackerClient extends I2PAppThread
url.getPort() < 0;
}
private class Tracker
private static class Tracker
{
String announce;
boolean isPrimary;

View File

@@ -23,6 +23,7 @@ package org.klomp.snark;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -37,6 +38,8 @@ public class TrackerInfo
private final String failure_reason;
private final int interval;
private final Set peers;
private int complete;
private int incomplete;
public TrackerInfo(InputStream in, byte[] my_id, MetaInfo metainfo)
throws IOException
@@ -68,11 +71,26 @@ public class TrackerInfo
throw new InvalidBEncodingException("No interval given");
else
interval = beInterval.getInt();
BEValue bePeers = (BEValue)m.get("peers");
if (bePeers == null)
throw new InvalidBEncodingException("No peer list");
peers = Collections.EMPTY_SET;
else
peers = getPeers(bePeers.getList(), my_id, metainfo);
BEValue bev = (BEValue)m.get("complete");
if (bev != null) try {
complete = bev.getInt();
if (complete < 0)
complete = 0;
} catch (InvalidBEncodingException ibe) {}
bev = (BEValue)m.get("incomplete");
if (bev != null) try {
incomplete = bev.getInt();
if (incomplete < 0)
incomplete = 0;
} catch (InvalidBEncodingException ibe) {}
}
}
@@ -115,6 +133,12 @@ public class TrackerInfo
return peers;
}
public int getPeerCount()
{
int pc = peers == null ? 0 : peers.size();
return Math.max(pc, complete + incomplete - 1);
}
public String getFailureReason()
{
return failure_reason;
@@ -132,6 +156,8 @@ public class TrackerInfo
return "TrackerInfo[FAILED: " + failure_reason + "]";
else
return "TrackerInfo[interval=" + interval
+ (complete > 0 ? (", complete=" + complete) : "" )
+ (incomplete > 0 ? (", incomplete=" + incomplete) : "" )
+ ", peers=" + peers + "]";
}
}

View File

@@ -59,6 +59,12 @@ public class I2PSnarkServlet extends HttpServlet {
_manager.start();
}
@Override
public void destroy() {
_manager.stop();
super.destroy();
}
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");

View File

@@ -124,13 +124,13 @@ class HTTPResponseOutputStream extends FilterOutputStream {
* Tweak that first HTTP response line (HTTP 200 OK, etc)
*
*/
protected String filterResponseLine(String line) {
protected static String filterResponseLine(String line) {
return line;
}
/** we ignore any potential \r, since we trim it on write anyway */
private static final byte NL = '\n';
private boolean isNL(byte b) { return (b == NL); }
private static boolean isNL(byte b) { return (b == NL); }
/** ok, received, now munge & write it */
private void writeHeader() throws IOException {
@@ -275,7 +275,8 @@ class HTTPResponseOutputStream extends FilterOutputStream {
_context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded, end-start);
}
}
private class InternalGZIPInputStream extends GZIPInputStream {
private static class InternalGZIPInputStream extends GZIPInputStream {
public InternalGZIPInputStream(InputStream in) throws IOException {
super(in);
}
@@ -318,6 +319,7 @@ class HTTPResponseOutputStream extends FilterOutputStream {
return super.toString() + ": " + _in;
}
/*******
public static void main(String args[]) {
String simple = "HTTP/1.1 200 OK\n" +
"foo: bar\n" +
@@ -367,7 +369,6 @@ class HTTPResponseOutputStream extends FilterOutputStream {
"A:\n" +
"\n";
/* */
test("Simple", simple, true);
test("Filtered", filtered, true);
test("Filtered windows", winfilter, true);
@@ -382,7 +383,6 @@ class HTTPResponseOutputStream extends FilterOutputStream {
test("Invalid (bad headers)", invalid5, true);
test("Invalid (bad headers2)", invalid6, false);
test("Invalid (bad headers3)", invalid7, false);
/* */
}
private static void test(String name, String orig, boolean shouldPass) {
@@ -401,4 +401,5 @@ class HTTPResponseOutputStream extends FilterOutputStream {
System.out.println("Properly fails with " + e.getMessage());
}
}
******/
}

View File

@@ -213,7 +213,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
sockMgr.getSession().destroySession();
} catch (I2PException ex) {
_log.error("Error destroying the session", ex);
System.exit(1);
//System.exit(1);
}
l.log("Server shut down.");
open = false;

View File

@@ -11,7 +11,6 @@ import java.util.Set;
import net.i2p.router.startup.ClientAppConfig;
import net.i2p.router.startup.LoadClientAppsJob;
import net.i2p.util.Log;
import org.mortbay.jetty.Server;
@@ -19,15 +18,19 @@ import org.mortbay.jetty.Server;
* Saves changes to clients.config or webapps.config
*/
public class ConfigClientsHandler extends FormHandler {
private Log configClient_log;
private Map _settings;
public ConfigClientsHandler() {
configClient_log = ContextHelper.getContext(null).logManager().getLog(ConfigClientsHandler.class);
}
@Override
protected void processForm() {
// set action for when CR is hit in a text input box
if (_action.length() <= 0) {
String url = getJettyString("pluginURL");
if (url != null && url.length() > 0)
_action = "Install Plugin";
else
_action = "Save Client Configuration";
}
if (_action.equals(_("Save Client Configuration"))) {
saveClientChanges();
return;
@@ -200,7 +203,7 @@ public class ConfigClientsHandler extends FormHandler {
return;
}
ClientAppConfig ca = clients.get(i);
LoadClientAppsJob.runClient(ca.className, ca.clientName, LoadClientAppsJob.parseArgs(ca.args), configClient_log);
LoadClientAppsJob.runClient(ca.className, ca.clientName, LoadClientAppsJob.parseArgs(ca.args), _log);
addFormNotice(_("Client") + ' ' + _(ca.clientName) + ' ' + _("started") + '.');
}

View File

@@ -43,11 +43,11 @@ public class ConfigClientsHelper extends HelperBase {
renderForm(buf, ""+cur, ca.clientName, false, !ca.disabled,
"webConsole".equals(ca.clientName) || "Web console".equals(ca.clientName),
ca.className + ((ca.args != null) ? " " + ca.args : ""), (""+cur).equals(_edit),
true, false, false, true);
true, false, false, true, !ca.disabled);
}
if ("new".equals(_edit))
renderForm(buf, "" + clients.size(), "", false, false, false, "", true, false, false, false, false);
renderForm(buf, "" + clients.size(), "", false, false, false, "", true, false, false, false, false, false);
buf.append("</table>\n");
return buf.toString();
}
@@ -65,7 +65,7 @@ public class ConfigClientsHelper extends HelperBase {
String val = props.getProperty(name);
renderForm(buf, app, app, !"addressbook".equals(app),
"true".equals(val), RouterConsoleRunner.ROUTERCONSOLE.equals(app), app + ".war",
false, false, false, false, false);
false, false, false, false, false, true);
}
}
buf.append("</table>\n");
@@ -149,7 +149,7 @@ public class ConfigClientsHelper extends HelperBase {
boolean enableStop = !Boolean.valueOf(appProps.getProperty("disableStop")).booleanValue();
renderForm(buf, app, app, false,
"true".equals(val), false, desc.toString(), false, false,
updateURL != null, enableStop, true);
updateURL != null, enableStop, true, true);
}
}
buf.append("</table>\n");
@@ -160,7 +160,7 @@ public class ConfigClientsHelper extends HelperBase {
private void renderForm(StringBuilder buf, String index, String name, boolean urlify,
boolean enabled, boolean ro, String desc, boolean edit,
boolean showEditButton, boolean showUpdateButton, boolean showStopButton,
boolean showDeleteButton) {
boolean showDeleteButton, boolean showStartButton) {
buf.append("<tr><td class=\"mediumtags\" align=\"right\" width=\"25%\">");
if (urlify && enabled) {
String link = "/";
@@ -183,7 +183,7 @@ public class ConfigClientsHelper extends HelperBase {
buf.append("disabled=\"true\" ");
}
buf.append("></td><td align=\"center\" width=\"15%\">");
if ((!enabled) && !edit) {
if (showStartButton && (!ro) && !edit) {
buf.append("<button type=\"submit\" name=\"action\" value=\"Start ").append(index).append("\" >" + _("Start") + "<span class=hide> ").append(index).append("</span></button>");
}
if (showEditButton && (!edit) && !ro)

View File

@@ -1,6 +1,8 @@
package net.i2p.router.web;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -31,9 +33,12 @@ public class NavHelper {
if (_apps.isEmpty())
return "";
StringBuilder buf = new StringBuilder(256);
for (Iterator<String> iter = _apps.keySet().iterator(); iter.hasNext(); ) {
String name = iter.next();
List<String> l = new ArrayList(_apps.keySet());
Collections.sort(l);
for (String name : l) {
String path = _apps.get(name);
if (path == null)
continue;
buf.append(" <a target=\"_top\" href=\"").append(path).append("\">");
buf.append(name).append("</a>");
}

View File

@@ -286,11 +286,11 @@ public class NetDbRenderer {
buf.append("<b>").append(DataHelper.stripHTML(style)).append(":</b> ");
int cost = addr.getCost();
if (!((style.equals("SSU") && cost == 5) || (style.equals("NTCP") && cost == 10)))
buf.append('[').append("cost").append('=').append("" + cost).append("] ");
buf.append('[').append(_("cost")).append('=').append("" + cost).append("] ");
for (Iterator optIter = addr.getOptions().keySet().iterator(); optIter.hasNext(); ) {
String name = (String)optIter.next();
String val = addr.getOptions().getProperty(name);
buf.append('[').append(DataHelper.stripHTML(name)).append('=').append(DataHelper.stripHTML(val)).append("] ");
buf.append('[').append(_(DataHelper.stripHTML(name))).append('=').append(DataHelper.stripHTML(val)).append("] ");
}
}
buf.append("</td></tr>\n");

View File

@@ -35,7 +35,7 @@ import org.mortbay.jetty.Server;
* @author zzz
*/
public class PluginStarter implements Runnable {
private RouterContext _context;
protected RouterContext _context;
static final String PREFIX = "plugin.";
static final String ENABLED = ".startOnLoad";
private static final String[] STANDARD_WEBAPPS = { "i2psnark", "i2ptunnel", "susidns",
@@ -223,7 +223,8 @@ public class PluginStarter implements Runnable {
if (name != null && name.length() > 0)
NavHelper.unregisterApp(name);
log.error("Stopping plugin: " + appName);
if (log.shouldLog(Log.WARN))
log.warn("Stopping plugin: " + appName);
return true;
}
@@ -426,7 +427,8 @@ public class PluginStarter implements Runnable {
}
try {
addPath(f.toURI().toURL());
log.error("INFO: Adding plugin to classpath: " + f);
if (log.shouldLog(Log.WARN))
log.warn("INFO: Adding plugin to classpath: " + f);
} catch (Exception e) {
log.error("Plugin client " + clientName + " bad classpath element: " + f, e);
}

View File

@@ -0,0 +1,40 @@
package net.i2p.router.web;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
/**
* Stop all plugins that are installed
*
* @since 0.7.13
* @author zzz
*/
public class PluginStopper extends PluginStarter {
public PluginStopper(RouterContext ctx) {
super(ctx);
}
@Override
public void run() {
stopPlugins(_context);
}
/**
* Stop all plugins
* (whether or not they were ever started)
*
* this shouldn't throw anything
*/
static void stopPlugins(RouterContext ctx) {
Log log = ctx.logManager().getLog(PluginStopper.class);
for (String app : getPlugins()) {
try {
stopPlugin(ctx, app);
} catch (Throwable e) {
if (log.shouldLog(Log.WARN))
log.warn("Failed to stop plugin: " + app, e);
}
}
}
}

View File

@@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import net.i2p.I2PAppContext;
@@ -14,6 +15,8 @@ import net.i2p.util.EepGet;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.PartialEepGet;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
import net.i2p.util.VersionComparator;
/**
@@ -46,6 +49,20 @@ public class PluginUpdateChecker extends UpdateHandler {
super(ctx);
}
/** check all plugins */
public void update() {
Thread t = new I2PAppThread(new AllCheckerRunner(), "AllAppChecker", true);
t.start();
}
public class AllCheckerRunner implements Runnable {
public void run() {
List<String> plugins = PluginStarter.getPlugins();
// TODO
}
}
/** check a single plugin */
public void update(String appName) {
// don't block waiting for the other one to finish
if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS))) {
@@ -84,6 +101,21 @@ public class PluginUpdateChecker extends UpdateHandler {
return false;
}
private void scheduleStatusClean(String msg) {
SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 60*60*1000);
}
private class Cleaner implements SimpleTimer.TimedEvent {
private String _msg;
public Cleaner(String msg) {
_msg = msg;
}
public void timeReached() {
if (_msg.equals(getStatus()))
updateStatus("");
}
}
public class PluginUpdateCheckerRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
ByteArrayOutputStream _baos;
@@ -116,17 +148,22 @@ public class PluginUpdateChecker extends UpdateHandler {
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
boolean newer = (new VersionComparator()).compare(newVersion, _oldVersion) > 0;
String msg;
if (newer)
updateStatus("<b>" + _("New plugin version {0} is available", newVersion) + "</b>");
msg = "<b>" + _("New plugin version {0} is available", newVersion) + "</b>";
else
updateStatus("<b>" + _("No new version is available for plugin {0}", _appName) + "</b>");
msg = "<b>" + _("No new version is available for plugin {0}", _appName) + "</b>";
updateStatus(msg);
scheduleStatusClean(msg);
}
@Override
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
File f = new File(_updateFile);
f.delete();
updateStatus("<b>" + _("Update check failed for plugin {0}", _appName) + "</b>");
String msg = "<b>" + _("Update check failed for plugin {0}", _appName) + "</b>";
updateStatus(msg);
scheduleStatusClean(msg);
}
}
}

View File

@@ -16,6 +16,8 @@ import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
import net.i2p.util.VersionComparator;
/**
@@ -89,6 +91,21 @@ public class PluginUpdateHandler extends UpdateHandler {
return false;
}
private void scheduleStatusClean(String msg) {
SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 60*60*1000);
}
private class Cleaner implements SimpleTimer.TimedEvent {
private String _msg;
public Cleaner(String msg) {
_msg = msg;
}
public void timeReached() {
if (_msg.equals(getStatus()))
updateStatus("");
}
}
public class PluginUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
public PluginUpdateRunner(String url) {
@@ -136,7 +153,7 @@ public class PluginUpdateHandler extends UpdateHandler {
File appDir = new File(_context.getAppDir(), PLUGIN_DIR);
if ((!appDir.exists()) && (!appDir.mkdir())) {
f.delete();
updateStatus("<b>" + _("Cannot create plugin directory {0}", appDir.getAbsolutePath()) + "</b>");
statusDone("<b>" + _("Cannot create plugin directory {0}", appDir.getAbsolutePath()) + "</b>");
return;
}
@@ -145,7 +162,7 @@ public class PluginUpdateHandler extends UpdateHandler {
// extract to a zip file whether the sig is good or not, so we can get the properties file
String err = up.migrateFile(f, to);
if (err != null) {
updateStatus("<b>" + err + ' ' + _("from {0}", url) + " </b>");
statusDone("<b>" + err + ' ' + _("from {0}", url) + " </b>");
f.delete();
to.delete();
return;
@@ -155,7 +172,7 @@ public class PluginUpdateHandler extends UpdateHandler {
f.delete();
to.delete();
FileUtil.rmdir(tempDir, false);
updateStatus("<b>" + _("Plugin from {0} is corrupt", url) + "</b>");
statusDone("<b>" + _("Plugin from {0} is corrupt", url) + "</b>");
return;
}
File installProps = new File(tempDir, "plugin.config");
@@ -166,7 +183,7 @@ public class PluginUpdateHandler extends UpdateHandler {
f.delete();
to.delete();
FileUtil.rmdir(tempDir, false);
updateStatus("<b>" + _("Plugin from {0} does not contain the required configuration file", url) + "</b>");
statusDone("<b>" + _("Plugin from {0} does not contain the required configuration file", url) + "</b>");
return;
}
// we don't need this anymore, we will unzip again
@@ -179,7 +196,7 @@ public class PluginUpdateHandler extends UpdateHandler {
f.delete();
to.delete();
//updateStatus("<b>" + "Plugin contains an invalid key" + ' ' + pubkey + ' ' + signer + "</b>");
updateStatus("<b>" + _("Plugin from {0} contains an invalid key", url) + "</b>");
statusDone("<b>" + _("Plugin from {0} contains an invalid key", url) + "</b>");
return;
}
@@ -198,7 +215,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (!signer.equals(signingKeyName)) {
f.delete();
to.delete();
updateStatus("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
statusDone("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
return;
}
} else {
@@ -207,7 +224,7 @@ public class PluginUpdateHandler extends UpdateHandler {
// bad or duplicate key
f.delete();
to.delete();
updateStatus("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
statusDone("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
return;
}
// ...and try the verify again
@@ -216,7 +233,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (!signer.equals(signingKeyName)) {
f.delete();
to.delete();
updateStatus("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
statusDone("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
return;
}
}
@@ -231,12 +248,12 @@ public class PluginUpdateHandler extends UpdateHandler {
version.indexOf("<") >= 0 || version.indexOf(">") >= 0 ||
appName.startsWith(".") || appName.indexOf("/") >= 0 || appName.indexOf("\\") >= 0) {
to.delete();
updateStatus("<b>" + _("Plugin from {0} has invalid name or version", url) + "</b>");
statusDone("<b>" + _("Plugin from {0} has invalid name or version", url) + "</b>");
return;
}
if (!version.equals(sudVersion)) {
to.delete();
updateStatus("<b>" + _("Plugin {0} has mismatched versions", appName) + "</b>");
statusDone("<b>" + _("Plugin {0} has mismatched versions", appName) + "</b>");
return;
}
@@ -244,7 +261,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (minVersion != null &&
(new VersionComparator()).compare(CoreVersion.VERSION, minVersion) < 0) {
to.delete();
updateStatus("<b>" + _("This plugin requires I2P version {0} or higher", minVersion) + "</b>");
statusDone("<b>" + _("This plugin requires I2P version {0} or higher", minVersion) + "</b>");
return;
}
@@ -252,7 +269,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (minVersion != null &&
(new VersionComparator()).compare(System.getProperty("java.version"), minVersion) < 0) {
to.delete();
updateStatus("<b>" + _("This plugin requires Java version {0} or higher", minVersion) + "</b>");
statusDone("<b>" + _("This plugin requires Java version {0} or higher", minVersion) + "</b>");
return;
}
@@ -260,7 +277,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (destDir.exists()) {
if (Boolean.valueOf(props.getProperty("install-only")).booleanValue()) {
to.delete();
updateStatus("<b>" + _("Downloaded plugin is for new installs only, but the plugin is already installed", url) + "</b>");
statusDone("<b>" + _("Downloaded plugin is for new installs only, but the plugin is already installed", url) + "</b>");
return;
}
@@ -272,7 +289,7 @@ public class PluginUpdateHandler extends UpdateHandler {
} catch (IOException ioe) {
to.delete();
FileUtil.rmdir(tempDir, false);
updateStatus("<b>" + _("Installed plugin does not contain the required configuration file", url) + "</b>");
statusDone("<b>" + _("Installed plugin does not contain the required configuration file", url) + "</b>");
return;
}
String oldPubkey = oldProps.getProperty("key");
@@ -280,28 +297,28 @@ public class PluginUpdateHandler extends UpdateHandler {
String oldAppName = props.getProperty("name");
if ((!pubkey.equals(oldPubkey)) || (!signer.equals(oldKeyName)) || (!appName.equals(oldAppName))) {
to.delete();
updateStatus("<b>" + _("Signature of downloaded plugin does not match installed plugin") + "</b>");
statusDone("<b>" + _("Signature of downloaded plugin does not match installed plugin") + "</b>");
return;
}
String oldVersion = oldProps.getProperty("version");
if (oldVersion == null ||
(new VersionComparator()).compare(oldVersion, version) >= 0) {
to.delete();
updateStatus("<b>" + _("Downloaded plugin version {0} is not newer than installed plugin", version) + "</b>");
statusDone("<b>" + _("Downloaded plugin version {0} is not newer than installed plugin", version) + "</b>");
return;
}
minVersion = ConfigClientsHelper.stripHTML(props, "min-installed-version");
if (minVersion != null &&
(new VersionComparator()).compare(minVersion, oldVersion) > 0) {
to.delete();
updateStatus("<b>" + _("Plugin update requires installed plugin version {0} or higher", minVersion) + "</b>");
statusDone("<b>" + _("Plugin update requires installed plugin version {0} or higher", minVersion) + "</b>");
return;
}
String maxVersion = ConfigClientsHelper.stripHTML(props, "max-installed-version");
if (maxVersion != null &&
(new VersionComparator()).compare(maxVersion, oldVersion) < 0) {
to.delete();
updateStatus("<b>" + _("Plugin update requires installed plugin version {0} or lower", maxVersion) + "</b>");
statusDone("<b>" + _("Plugin update requires installed plugin version {0} or lower", maxVersion) + "</b>");
return;
}
@@ -318,12 +335,12 @@ public class PluginUpdateHandler extends UpdateHandler {
} else {
if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
to.delete();
updateStatus("<b>" + _("Plugin is for upgrades only, but the plugin is not installed") + "</b>");
statusDone("<b>" + _("Plugin is for upgrades only, but the plugin is not installed") + "</b>");
return;
}
if (!destDir.mkdir()) {
to.delete();
updateStatus("<b>" + _("Cannot create plugin directory {0}", destDir.getAbsolutePath()) + "</b>");
statusDone("<b>" + _("Cannot create plugin directory {0}", destDir.getAbsolutePath()) + "</b>");
return;
}
}
@@ -331,16 +348,16 @@ public class PluginUpdateHandler extends UpdateHandler {
// Finally, extract the zip to the plugin directory
if (!FileUtil.extractZip(to, destDir)) {
to.delete();
updateStatus("<b>" + _("Failed to install plugin in {0}", destDir.getAbsolutePath()) + "</b>");
statusDone("<b>" + _("Failed to install plugin in {0}", destDir.getAbsolutePath()) + "</b>");
return;
}
to.delete();
if (Boolean.valueOf(props.getProperty("dont-start-at-install")).booleanValue()) {
if (Boolean.valueOf(props.getProperty("router-restart-required")).booleanValue())
updateStatus("<b>" + _("Plugin {0} installed, router restart required", appName) + "</b>");
statusDone("<b>" + _("Plugin {0} installed, router restart required", appName) + "</b>");
else {
updateStatus("<b>" + _("Plugin {0} installed", appName) + "</b>");
statusDone("<b>" + _("Plugin {0} installed", appName) + "</b>");
Properties pluginProps = PluginStarter.pluginProperties();
pluginProps.setProperty(PluginStarter.PREFIX + appName + PluginStarter.ENABLED, "false");
PluginStarter.storePluginProperties(pluginProps);
@@ -349,11 +366,11 @@ public class PluginUpdateHandler extends UpdateHandler {
// start everything
try {
if (PluginStarter.startPlugin(_context, appName))
updateStatus("<b>" + _("Plugin {0} installed and started", appName) + "</b>");
statusDone("<b>" + _("Plugin {0} installed and started", appName) + "</b>");
else
updateStatus("<b>" + _("Plugin {0} installed but failed to start, check logs", appName) + "</b>");
statusDone("<b>" + _("Plugin {0} installed but failed to start, check logs", appName) + "</b>");
} catch (Throwable e) {
updateStatus("<b>" + _("Plugin {0} installed but failed to start", appName) + ": " + e + "</b>");
statusDone("<b>" + _("Plugin {0} installed but failed to start", appName) + ": " + e + "</b>");
_log.error("Error starting plugin " + appName, e);
}
}
@@ -363,8 +380,14 @@ public class PluginUpdateHandler extends UpdateHandler {
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
File f = new File(_updateFile);
f.delete();
updateStatus("<b>" + _("Failed to download plugin from {0}", url) + "</b>");
statusDone("<b>" + _("Failed to download plugin from {0}", url) + "</b>");
}
private void statusDone(String msg) {
updateStatus(msg);
scheduleStatusClean(msg);
}
}
@Override

View File

@@ -190,9 +190,11 @@ public class RouterConsoleRunner {
List<RouterContext> contexts = RouterContext.listContexts();
if (contexts != null) {
if (PluginStarter.pluginsEnabled(contexts.get(0))) {
t = new I2PAppThread(new PluginStarter(contexts.get(0)), "PluginStarter", true);
RouterContext ctx = contexts.get(0);
if (PluginStarter.pluginsEnabled(ctx)) {
t = new I2PAppThread(new PluginStarter(ctx), "PluginStarter", true);
t.start();
ctx.addShutdownTask(new PluginStopper(ctx));
}
}
}

View File

@@ -43,9 +43,17 @@ public class WebAppStarter {
/**
* add but don't start
* This is used only by RouterConsoleRunner, which adds all the webapps first
* and then starts all at once.
*/
static WebApplicationContext addWebApp(I2PAppContext ctx, Server server, String appName, String warPath, File tmpdir) throws IOException {
// Jetty will happily load one context on top of another without stopping
// the first one, so we remove any previous one here
try {
stopWebApp(server, appName);
} catch (Throwable t) {}
WebApplicationContext wac = server.addWebApplication("/"+ appName, warPath);
tmpdir.mkdir();
wac.setTempDirectory(tmpdir);
@@ -64,7 +72,7 @@ public class WebAppStarter {
}
/**
* stop it
* stop it and remove the context
* @throws just about anything, caller would be wise to catch Throwable
*/
static void stopWebApp(Server server, String appName) {
@@ -74,6 +82,9 @@ public class WebAppStarter {
// false -> not graceful
wac.stop(false);
} catch (InterruptedException ie) {}
try {
server.removeContext(wac);
} catch (IllegalStateException ise) {}
}
/** see comments in ConfigClientsHandler */

View File

@@ -71,5 +71,30 @@ class Dummy {
_("Transport");
_("Tunnels");
_("udp");
// parameters in transport addresses (netdb.jsp)
// may or may not be worth translating
_("host");
_("key");
_("port");
// capabilities
_("caps");
// introducer host
_("ihost0");
_("ihost1");
_("ihost2");
// introducer port
_("iport0");
_("iport1");
_("iport2");
// introducer key
_("ikey0");
_("ikey1");
_("ikey2");
// introducer tag
_("itag0");
_("itag1");
_("itag2");
}
}

View File

@@ -30,7 +30,9 @@ button span.hide{
<% String prev = System.getProperty("net.i2p.router.web.ConfigClientsHandler.nonce");
if (prev != null) System.setProperty("net.i2p.router.web.ConfigClientsHandler.noncePrev", prev);
System.setProperty("net.i2p.router.web.ConfigClientsHandler.nonce", new java.util.Random().nextLong()+""); %>
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigClientsHandler.nonce")%>" />
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigClientsHandler.nonce")%>" >
<% /* set hidden default */ %>
<button type="submit" name="action" value="" style="display:none" >Cancel</button>
<h3><%=intl._("Client Configuration")%></h3><p>
<%=intl._("The Java clients listed below are started by the router and run in the same JVM.")%>
</p><div class="wideload">
@@ -56,7 +58,7 @@ button span.hide{
<input type="submit" name="action" value="<%=intl._("Save WebApp Configuration")%>" />
</div></div>
<% if (clientshelper.showPlugins()) { %>
<h3><a name="webapp"></a><%=intl._("Plugin Configuration")%></h3><p>
<h3><a name="pconfig"></a><%=intl._("Plugin Configuration")%></h3><p>
<%=intl._("The plugins listed below are started by the webConsole client.")%>
</p><div class="wideload"><p>
<jsp:getProperty name="clientshelper" property="form3" />

View File

@@ -25,7 +25,9 @@
<% String prev = System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce");
if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev);
System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %>
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce")%>" />
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce")%>" >
<% /* set hidden default */ %>
<input type="submit" name="action" value="" style="display:none" >
<h3><%=intl._("Check for I2P and news updates")%></h3>
<div class="wideload"><table border="0" cellspacing="5">
<tr><td colspan="2"></tr>
@@ -59,6 +61,6 @@
<% } // if canInstall %>
<tr class="tablefooter"><td colspan="2">
<div class="formaction">
<input type="submit" name="action" value="<%=intl._("Save")%>" />
<input type="reset" value="<%=intl._("Cancel")%>" />
<input type="reset" value="<%=intl._("Cancel")%>" >
<input type="submit" name="action" value="<%=intl._("Save")%>" >
</div></td></tr></table></div></form></div></div></body></html>

View File

@@ -264,8 +264,30 @@
</delete>
</target>
<target name="preppkg" depends="preppkg-linux, buildexe">
<target name="preppkg" depends="preppkg-linux, preppkg-windows">
<copy file="build/jbigi.jar" todir="pkg-temp/lib" />
<copy todir="pkg-temp/lib/wrapper/freebsd/">
<fileset dir="installer/lib/wrapper/freebsd/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/macosx/">
<fileset dir="installer/lib/wrapper/macosx/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/solaris/">
<fileset dir="installer/lib/wrapper/solaris/" />
</copy>
</target>
<target name="preppkg-windows-only" depends="preppkg-windows">
<!-- rip the non-windows stuff out of jbigi.jar -->
<mkdir dir="tmpextract" />
<unjar src="build/jbigi.jar" dest="tmpextract/" />
<jar destfile="pkg-temp/lib/jbigi.jar" >
<fileset dir="tmpextract/" includes="*windows*" />
</jar>
<delete dir="tmpextract/" />
</target>
<target name="preppkg-windows" depends="preppkg-base, buildexe">
<copy file="i2p.exe" todir="pkg-temp/" failonerror="false" />
<copy file="apps/systray/java/lib/systray4j.dll" todir="pkg-temp/lib" />
<copy file="apps/systray/java/resources/iggy.ico" todir="pkg-temp/icons" />
@@ -276,15 +298,6 @@
<copy file="installer/resources/install_i2p_service_winnt.bat" todir="pkg-temp/" />
<copy file="installer/resources/postinstall.bat" todir="pkg-temp/" />
<copy file="installer/resources/uninstall_i2p_service_winnt.bat" todir="pkg-temp/" />
<copy todir="pkg-temp/lib/wrapper/freebsd/">
<fileset dir="installer/lib/wrapper/freebsd/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/macosx/">
<fileset dir="installer/lib/wrapper/macosx/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/solaris/">
<fileset dir="installer/lib/wrapper/solaris/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/win32/">
<fileset dir="installer/lib/wrapper/win32/" />
</copy>
@@ -301,7 +314,22 @@
<delete dir="tmpextract/" />
</target>
<target name="preppkg-linux" depends="build, preplicenses, prepconsoleDocs">
<target name="preppkg-linux" depends="preppkg-base">
<copy file="installer/resources/runplain.sh" todir="pkg-temp/" />
<copy file="apps/i2psnark/launch-i2psnark" todir="pkg-temp/" />
<copy file="installer/resources/eepget" todir="pkg-temp/" />
<copy file="installer/resources/i2prouter" todir="pkg-temp/" />
<copy file="installer/resources/osid" todir="pkg-temp/" />
<copy file="installer/resources/postinstall.sh" todir="pkg-temp/" />
<copy todir="pkg-temp/lib/wrapper/linux/">
<fileset dir="installer/lib/wrapper/linux/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/linux64/">
<fileset dir="installer/lib/wrapper/linux64/" />
</copy>
</target>
<target name="preppkg-base" depends="build, preplicenses, prepconsoleDocs">
<copy file="build/i2p.jar" todir="pkg-temp/lib/" />
<copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
@@ -320,7 +348,6 @@
<copy file="build/BOB.jar" todir="pkg-temp/lib/" />
<copy file="build/systray.jar" todir="pkg-temp/lib" />
<copy file="build/i2psnark.jar" todir="pkg-temp/lib/" />
<copy file="installer/resources/runplain.sh" todir="pkg-temp/" />
<copy file="apps/systray/java/lib/systray4j.jar" todir="pkg-temp/lib" />
<copy file="build/i2ptunnel.war" todir="pkg-temp/webapps/" />
<copy file="build/routerconsole.war" todir="pkg-temp/webapps/" />
@@ -330,24 +357,13 @@
<copy file="apps/susidns/src/WEB-INF/lib/jstl.jar" todir="pkg-temp/lib/" />
<copy file="apps/susidns/src/WEB-INF/lib/standard.jar" todir="pkg-temp/lib/" />
<copy file="build/i2psnark.war" todir="pkg-temp/webapps/" />
<copy file="apps/i2psnark/launch-i2psnark" todir="pkg-temp/" />
<copy file="apps/i2psnark/jetty-i2psnark.xml" todir="pkg-temp/" />
<copy file="apps/i2psnark/i2psnark.config" todir="pkg-temp/" />
<copy file="installer/resources/blocklist.txt" todir="pkg-temp/" />
<copy file="installer/resources/clients.config" todir="pkg-temp/" />
<copy file="installer/resources/eepget" todir="pkg-temp/" />
<copy file="installer/resources/i2prouter" todir="pkg-temp/" />
<copy file="installer/resources/i2ptunnel.config" todir="pkg-temp/" />
<copy file="installer/resources/osid" todir="pkg-temp/" />
<copy file="installer/resources/postinstall.sh" todir="pkg-temp/" />
<copy file="installer/resources/systray.config" todir="pkg-temp/" />
<copy file="installer/resources/wrapper.config" todir="pkg-temp/" />
<copy todir="pkg-temp/lib/wrapper/linux/">
<fileset dir="installer/lib/wrapper/linux/" />
</copy>
<copy todir="pkg-temp/lib/wrapper/linux64/">
<fileset dir="installer/lib/wrapper/linux64/" />
</copy>
<copy file="installer/resources/hosts.txt" todir="pkg-temp/" />
<copy file="INSTALL-headless.txt" todir="pkg-temp/" />
<!-- overwrite the truncated history put in by the updater -->

View File

@@ -7,7 +7,11 @@
*/
package net.i2p.client.naming;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -87,13 +91,10 @@ public class HostsTxtNamingService extends NamingService {
List filenames = getFilenames();
for (int i = 0; i < filenames.size(); i++) {
String hostsfile = (String)filenames.get(i);
Properties hosts = new Properties();
try {
File f = new File(_context.getRouterDir(), hostsfile);
if ( (f.exists()) && (f.canRead()) ) {
DataHelper.loadProps(hosts, f, true);
String key = hosts.getProperty(hostname.toLowerCase());
String key = getKey(f, hostname.toLowerCase());
if ( (key != null) && (key.trim().length() > 0) ) {
d = lookupBase64(key);
putCache(hostname, d);
@@ -168,4 +169,30 @@ public class HostsTxtNamingService extends NamingService {
}
return null;
}
/**
* Better than DataHelper.loadProps(), doesn't load the whole file into memory,
* and stops when it finds a match.
*
* @param host lower case
* @since 0.7.13
*/
private static String getKey(File file, String host) throws IOException {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"), 16*1024);
String line = null;
while ( (line = in.readLine()) != null) {
if (!line.toLowerCase().startsWith(host + '='))
continue;
if (line.indexOf('#') > 0) // trim off any end of line comment
line = line.substring(0, line.indexOf('#')).trim();
int split = line.indexOf('=');
return line.substring(split+1); //.trim() ??????????????
}
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
}
return null;
}
}

View File

@@ -267,6 +267,8 @@ public class PrivateKeyFile {
StringBuilder s = new StringBuilder(128);
s.append("Dest: ");
s.append(this.dest != null ? this.dest.toBase64() : "null");
s.append("\nB32: ");
s.append(this.dest != null ? Base32.encode(this.dest.calculateHash().getData()) + ".b32.i2p" : "null");
s.append("\nContains: ");
s.append(this.dest);
s.append("\nPrivate Key: ");

View File

@@ -455,6 +455,8 @@ public class EepGet {
_listeners.get(i).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
if (_log.shouldLog(Log.WARN))
_log.warn("ERR: doFetch failed " + ioe);
if (ioe instanceof MalformedURLException)
_keepFetching = false;
} finally {
if (_out != null) {
try {

View File

@@ -1,3 +1,44 @@
2010-04-02 zzz
* FloodfillPeerSelector: Adjust rankings again
2010-03-31 zzz
* FloodfillPeerSelector: Adjust rankings to try to
improve LeaseSet lookups
* HostsTxtNamingService: Don't load the whole hosts.txt
into memory for every lookup
2010-03-29 zzz
* build.xml: Prep for a windows-only pkg
* configclients.jsp:
- Always show start button for webapps and plugins
* configclients.jsp, configupdate.jsp:
- Fix submission when entering CR in a text box
* EepGet: Don't retry after a MalformedURLException
* HTTPResponseOutputStream: More static
* Plugins:
- Stop all plugins at shutdown
- Log tweaks
* WebApps:
- Remove the WAC after stopping it
- Stop a WAC before starting it to prevent dups
- Implement destroy() in addressbook to prevent dups
- Implement destroy() in i2psnark to prevent dups
2010-03-25 zzz
* configclients.jsp: Fix dup anchor
* Console: Sort plugin links in summary bar
* i2psnark:
- Send numwant=0 if we don't need peers
- Report returned complete and incomplete counts
if higher than peer count
- Allow missing peer list
- Log tweaks
* netdb.jsp: Tag transport properties
* Plugins: Remove final check and install console
messages after a while
* PrivateKeyFile: Add b32 output
* Reseed: Add another host
2010-03-18 zzz
* Blocklist, CommSystem, FIFOBandwidth, TransportManager,
OutNetMessage, InNetMessagePool:
@@ -48,6 +89,10 @@
not sure why taking them from the tail "reduces latency"
- Java 5 cleanup
2010-03-17 zzz
* I2PTunnel: Disable nonce checking when console password set
* Reseed: Add another host
* 2010-03-15 0.7.12 released
2010-03-13 zzz

View File

@@ -13,12 +13,12 @@ import net.i2p.CoreVersion;
/**
* Expose a version string
*
n */
*/
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 = 5;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -112,7 +112,7 @@ class FloodfillPeerSelector extends PeerSelector {
private static final int NO_FAIL_STORE_OK = 10*60*1000;
private static final int NO_FAIL_STORE_GOOD = NO_FAIL_STORE_OK * 2;
/** this must be longer than the max streaming timeout (60s) */
private static final int NO_FAIL_LOOKUP_OK = 2*60*1000;
private static final int NO_FAIL_LOOKUP_OK = 75*1000;
private static final int NO_FAIL_LOOKUP_GOOD = NO_FAIL_LOOKUP_OK * 3;
private static final int MAX_GOOD_RESP_TIME = 5*1000;
@@ -135,8 +135,11 @@ class FloodfillPeerSelector extends PeerSelector {
maxFailRate = 100d; // disable
}
// 8 == FNDF.MAX_TO_FLOOD + 1
int limit = Math.max(8, howMany);
limit = Math.min(limit, ffs.size());
// split sorted list into 3 sorted lists
for (int i = 0; found < howMany && i < ffs.size(); i++) {
for (int i = 0; found < howMany && i < limit; i++) {
Hash entry = sorted.first();
sorted.remove(entry);
if (entry == null)

View File

@@ -36,7 +36,10 @@ public class Reseeder {
// Reject unreasonably big files, because we download into a ByteArrayOutputStream.
private static final long MAX_RESEED_RESPONSE_SIZE = 1024 * 1024;
private static final String DEFAULT_SEED_URL = "http://a.netdb.i2p2.de/,http://b.netdb.i2p2.de/,http://c.netdb.i2p2.de/,http://reseed.i2p-projekt.de/,http://i2pbote.net/netDb/,http://r31453.ovh.net/static_media/netDb/";
private static final String DEFAULT_SEED_URL =
"http://a.netdb.i2p2.de/,http://b.netdb.i2p2.de/,http://c.netdb.i2p2.de/," +
"http://reseed.i2p-projekt.de/,http://i2pbote.net/netDb/,http://r31453.ovh.net/static_media/netDb/," +
"http://p2i.mine.nu/netDb/";
private static final String PROP_INPROGRESS = "net.i2p.router.web.ReseedHandler.reseedInProgress";
private static final String PROP_ERROR = "net.i2p.router.web.ReseedHandler.errorMessage";
private static final String PROP_STATUS = "net.i2p.router.web.ReseedHandler.statusMessage";