forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head d289b6cafae6b23ce699dca11dbb3e993c8f827f)
to branch 'i2p.i2p.zzz.test' (head e2c6210696c78c54650ff345f18ad62b4543a18b)
This commit is contained in:
@ -12,7 +12,19 @@ public class LogsHelper extends HelperBase {
|
|||||||
|
|
||||||
/** @since 0.8.11 */
|
/** @since 0.8.11 */
|
||||||
public String getJettyVersion() {
|
public String getJettyVersion() {
|
||||||
return Version.getImplVersion();
|
return jettyVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.13 */
|
||||||
|
static String jettyVersion() {
|
||||||
|
try {
|
||||||
|
String rv = Version.getImplVersion();
|
||||||
|
if (rv.startsWith("Jetty/"))
|
||||||
|
rv = rv.substring(6);
|
||||||
|
return rv;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLogs() {
|
public String getLogs() {
|
||||||
|
@ -376,9 +376,8 @@ public class NetDbRenderer {
|
|||||||
int cost = addr.getCost();
|
int cost = addr.getCost();
|
||||||
if (!((style.equals("SSU") && cost == 5) || (style.equals("NTCP") && cost == 10)))
|
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("] ");
|
||||||
Properties p = new OrderedProperties();
|
Map p = addr.getOptionsMap();
|
||||||
p.putAll(addr.getOptions());
|
for (Map.Entry e : (Set<Map.Entry>) p.entrySet()) {
|
||||||
for (Map.Entry e : p.entrySet()) {
|
|
||||||
String name = (String) e.getKey();
|
String name = (String) e.getKey();
|
||||||
String val = (String) e.getValue();
|
String val = (String) e.getValue();
|
||||||
buf.append('[').append(_(DataHelper.stripHTML(name))).append('=').append(DataHelper.stripHTML(val)).append("] ");
|
buf.append('[').append(_(DataHelper.stripHTML(name))).append('=').append(DataHelper.stripHTML(val)).append("] ");
|
||||||
@ -387,9 +386,10 @@ public class NetDbRenderer {
|
|||||||
buf.append("</td></tr>\n");
|
buf.append("</td></tr>\n");
|
||||||
if (full) {
|
if (full) {
|
||||||
buf.append("<tr><td>" + _("Stats") + ": <br><code>");
|
buf.append("<tr><td>" + _("Stats") + ": <br><code>");
|
||||||
for (Iterator iter = info.getOptions().keySet().iterator(); iter.hasNext(); ) {
|
Map p = info.getOptionsMap();
|
||||||
String key = (String)iter.next();
|
for (Map.Entry e : (Set<Map.Entry>) p.entrySet()) {
|
||||||
String val = info.getOption(key);
|
String key = (String) e.getKey();
|
||||||
|
String val = (String) e.getValue();
|
||||||
buf.append(DataHelper.stripHTML(key)).append(" = ").append(DataHelper.stripHTML(val)).append("<br>\n");
|
buf.append(DataHelper.stripHTML(key)).append(" = ").append(DataHelper.stripHTML(val)).append("<br>\n");
|
||||||
}
|
}
|
||||||
buf.append("</code></td></tr>\n");
|
buf.append("</code></td></tr>\n");
|
||||||
@ -412,7 +412,7 @@ public class NetDbRenderer {
|
|||||||
if (style.equals("NTCP")) {
|
if (style.equals("NTCP")) {
|
||||||
rv |= NTCP;
|
rv |= NTCP;
|
||||||
} else if (style.equals("SSU")) {
|
} else if (style.equals("SSU")) {
|
||||||
if (addr.getOptions().getProperty("iport0") != null)
|
if (addr.getOption("iport0") != null)
|
||||||
rv |= SSUI;
|
rv |= SSUI;
|
||||||
else
|
else
|
||||||
rv |= SSU;
|
rv |= SSU;
|
||||||
|
@ -17,6 +17,7 @@ import java.util.Properties;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.i2p.CoreVersion;
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.router.Job;
|
import net.i2p.router.Job;
|
||||||
@ -27,6 +28,7 @@ import net.i2p.util.ConcurrentHashSet;
|
|||||||
import net.i2p.util.FileUtil;
|
import net.i2p.util.FileUtil;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.Translate;
|
import net.i2p.util.Translate;
|
||||||
|
import net.i2p.util.VersionComparator;
|
||||||
|
|
||||||
import org.mortbay.jetty.Server;
|
import org.mortbay.jetty.Server;
|
||||||
|
|
||||||
@ -95,6 +97,41 @@ public class PluginStarter implements Runnable {
|
|||||||
log.error("Cannot start nonexistent plugin: " + appName);
|
log.error("Cannot start nonexistent plugin: " + appName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Properties props = pluginProperties(ctx, appName);
|
||||||
|
String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
|
||||||
|
if (minVersion != null &&
|
||||||
|
(new VersionComparator()).compare(CoreVersion.VERSION, minVersion) < 0) {
|
||||||
|
String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
|
||||||
|
log.error(foo);
|
||||||
|
throw new Exception(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
|
||||||
|
if (minVersion != null &&
|
||||||
|
(new VersionComparator()).compare(System.getProperty("java.version"), minVersion) < 0) {
|
||||||
|
String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
|
||||||
|
log.error(foo);
|
||||||
|
throw new Exception(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
String jVersion = LogsHelper.jettyVersion();
|
||||||
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
|
||||||
|
if (minVersion != null &&
|
||||||
|
(new VersionComparator()).compare(minVersion, jVersion) > 0) {
|
||||||
|
String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
|
||||||
|
log.error(foo);
|
||||||
|
throw new Exception(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
String maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
||||||
|
if (maxVersion != null &&
|
||||||
|
(new VersionComparator()).compare(maxVersion, jVersion) < 0) {
|
||||||
|
String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
|
||||||
|
log.error(foo);
|
||||||
|
throw new Exception(foo);
|
||||||
|
}
|
||||||
|
|
||||||
if (log.shouldLog(Log.INFO))
|
if (log.shouldLog(Log.INFO))
|
||||||
log.info("Starting plugin: " + appName);
|
log.info("Starting plugin: " + appName);
|
||||||
|
|
||||||
@ -113,8 +150,8 @@ public class PluginStarter implements Runnable {
|
|||||||
// load and start things in clients.config
|
// load and start things in clients.config
|
||||||
File clientConfig = new File(pluginDir, "clients.config");
|
File clientConfig = new File(pluginDir, "clients.config");
|
||||||
if (clientConfig.exists()) {
|
if (clientConfig.exists()) {
|
||||||
Properties props = new Properties();
|
Properties cprops = new Properties();
|
||||||
DataHelper.loadProps(props, clientConfig);
|
DataHelper.loadProps(cprops, clientConfig);
|
||||||
List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
|
List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
|
||||||
runClientApps(ctx, pluginDir, clients, "start");
|
runClientApps(ctx, pluginDir, clients, "start");
|
||||||
}
|
}
|
||||||
@ -123,7 +160,7 @@ public class PluginStarter implements Runnable {
|
|||||||
Server server = WebAppStarter.getConsoleServer();
|
Server server = WebAppStarter.getConsoleServer();
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
File consoleDir = new File(pluginDir, "console");
|
File consoleDir = new File(pluginDir, "console");
|
||||||
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
Properties wprops = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
||||||
File webappDir = new File(consoleDir, "webapps");
|
File webappDir = new File(consoleDir, "webapps");
|
||||||
String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance());
|
String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance());
|
||||||
if (fileNames != null) {
|
if (fileNames != null) {
|
||||||
@ -138,7 +175,7 @@ public class PluginStarter implements Runnable {
|
|||||||
log.error("Skipping duplicate webapp " + warName + " in plugin " + appName);
|
log.error("Skipping duplicate webapp " + warName + " in plugin " + appName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String enabled = props.getProperty(RouterConsoleRunner.PREFIX + warName + ENABLED);
|
String enabled = wprops.getProperty(RouterConsoleRunner.PREFIX + warName + ENABLED);
|
||||||
if (! "false".equals(enabled)) {
|
if (! "false".equals(enabled)) {
|
||||||
if (log.shouldLog(Log.INFO))
|
if (log.shouldLog(Log.INFO))
|
||||||
log.info("Starting webapp: " + warName);
|
log.info("Starting webapp: " + warName);
|
||||||
@ -181,7 +218,6 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add summary bar link
|
// add summary bar link
|
||||||
Properties props = pluginProperties(ctx, appName);
|
|
||||||
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
|
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
|
||||||
if (name == null)
|
if (name == null)
|
||||||
name = ConfigClientsHelper.stripHTML(props, "consoleLinkName");
|
name = ConfigClientsHelper.stripHTML(props, "consoleLinkName");
|
||||||
|
@ -334,6 +334,21 @@ public class PluginUpdateHandler extends UpdateHandler {
|
|||||||
statusDone("<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;
|
return;
|
||||||
}
|
}
|
||||||
|
oldVersion = LogsHelper.jettyVersion();
|
||||||
|
minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
|
||||||
|
if (minVersion != null &&
|
||||||
|
(new VersionComparator()).compare(minVersion, oldVersion) > 0) {
|
||||||
|
to.delete();
|
||||||
|
statusDone("<b>" + _("Plugin requires Jetty version {0} or higher", minVersion) + "</b>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
|
||||||
|
if (maxVersion != null &&
|
||||||
|
(new VersionComparator()).compare(maxVersion, oldVersion) < 0) {
|
||||||
|
to.delete();
|
||||||
|
statusDone("<b>" + _("Plugin requires Jetty version {0} or lower", maxVersion) + "</b>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// check if it is running first?
|
// check if it is running first?
|
||||||
try {
|
try {
|
||||||
|
@ -118,6 +118,17 @@ public class DataHelper {
|
|||||||
public static Properties readProperties(InputStream rawStream)
|
public static Properties readProperties(InputStream rawStream)
|
||||||
throws DataFormatException, IOException {
|
throws DataFormatException, IOException {
|
||||||
Properties props = new OrderedProperties();
|
Properties props = new OrderedProperties();
|
||||||
|
readProperties(rawStream, props);
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ditto, load into an existing properties
|
||||||
|
* @param props the Properties to load into
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
public static Properties readProperties(InputStream rawStream, Properties props)
|
||||||
|
throws DataFormatException, IOException {
|
||||||
long size = readLong(rawStream, 2);
|
long size = readLong(rawStream, 2);
|
||||||
byte data[] = new byte[(int) size];
|
byte data[] = new byte[(int) size];
|
||||||
int read = read(rawStream, data);
|
int read = read(rawStream, data);
|
||||||
@ -1268,6 +1279,8 @@ public class DataHelper {
|
|||||||
* Why? Just because it has to be consistent so signing will work.
|
* Why? Just because it has to be consistent so signing will work.
|
||||||
* How to spec as returning the same type as the param?
|
* How to spec as returning the same type as the param?
|
||||||
* DEPRECATED - Only used by RouterInfo.
|
* DEPRECATED - Only used by RouterInfo.
|
||||||
|
*
|
||||||
|
* @return a new list
|
||||||
*/
|
*/
|
||||||
public static List<? extends DataStructure> sortStructures(Collection<? extends DataStructure> dataStructures) {
|
public static List<? extends DataStructure> sortStructures(Collection<? extends DataStructure> dataStructures) {
|
||||||
if (dataStructures == null) return Collections.EMPTY_LIST;
|
if (dataStructures == null) return Collections.EMPTY_LIST;
|
||||||
|
@ -124,16 +124,22 @@ public abstract class DatabaseEntry extends DataStructureImpl {
|
|||||||
/**
|
/**
|
||||||
* Configure the proof that the entity stands behind the info here
|
* Configure the proof that the entity stands behind the info here
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if already signed
|
||||||
*/
|
*/
|
||||||
public void setSignature(Signature signature) {
|
public void setSignature(Signature signature) {
|
||||||
|
if (_signature != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
_signature = signature;
|
_signature = signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign the structure using the supplied signing key
|
* Sign the structure using the supplied signing key
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if already signed
|
||||||
*/
|
*/
|
||||||
public void sign(SigningPrivateKey key) throws DataFormatException {
|
public void sign(SigningPrivateKey key) throws DataFormatException {
|
||||||
|
if (_signature != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
byte[] bytes = getBytes();
|
byte[] bytes = getBytes();
|
||||||
if (bytes == null) throw new DataFormatException("Not enough data to sign");
|
if (bytes == null) throw new DataFormatException("Not enough data to sign");
|
||||||
// now sign with the key
|
// now sign with the key
|
||||||
|
@ -12,6 +12,7 @@ package net.i2p.data;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -22,16 +23,24 @@ import net.i2p.util.OrderedProperties;
|
|||||||
/**
|
/**
|
||||||
* Defines a method of communicating with a router
|
* Defines a method of communicating with a router
|
||||||
*
|
*
|
||||||
|
* For efficiency, the options methods and structures here are unsynchronized.
|
||||||
|
* Initialize the structure with readBytes(), or call the setOptions().
|
||||||
|
* Don't change it after that.
|
||||||
|
*
|
||||||
|
* To ensure integrity of the RouterInfo, methods that change an element of the
|
||||||
|
* RouterInfo will throw an IllegalStateException after the RouterInfo is signed.
|
||||||
|
*
|
||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class RouterAddress extends DataStructureImpl {
|
public class RouterAddress extends DataStructureImpl {
|
||||||
private int _cost;
|
private int _cost;
|
||||||
private Date _expiration;
|
private Date _expiration;
|
||||||
private String _transportStyle;
|
private String _transportStyle;
|
||||||
private Properties _options;
|
private final Properties _options;
|
||||||
|
|
||||||
public RouterAddress() {
|
public RouterAddress() {
|
||||||
_cost = -1;
|
_cost = -1;
|
||||||
|
_options = new OrderedProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,28 +94,59 @@ public class RouterAddress extends DataStructureImpl {
|
|||||||
/**
|
/**
|
||||||
* Configure the type of transport that must be used to communicate on this address
|
* Configure the type of transport that must be used to communicate on this address
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if was already set
|
||||||
*/
|
*/
|
||||||
public void setTransportStyle(String transportStyle) {
|
public void setTransportStyle(String transportStyle) {
|
||||||
|
if (_transportStyle != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
_transportStyle = transportStyle;
|
_transportStyle = transportStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the transport specific options necessary for communication
|
* Retrieve the transport specific options necessary for communication
|
||||||
*
|
*
|
||||||
|
* @deprecated use getOptionsMap()
|
||||||
|
* @return sorted, non-null, NOT a copy, do not modify
|
||||||
*/
|
*/
|
||||||
public Properties getOptions() {
|
public Properties getOptions() {
|
||||||
return _options;
|
return _options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the transport specific options necessary for communication
|
* Retrieve the transport specific options necessary for communication
|
||||||
*
|
*
|
||||||
|
* @return an unmodifiable view, non-null, sorted
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
public Map getOptionsMap() {
|
||||||
|
return Collections.unmodifiableMap(_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
public String getOption(String opt) {
|
||||||
|
return _options.getProperty(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the transport specific options necessary for communication.
|
||||||
|
* Makes a copy.
|
||||||
|
* @param options non-null
|
||||||
|
* @throws IllegalStateException if was already set
|
||||||
*/
|
*/
|
||||||
public void setOptions(Properties options) {
|
public void setOptions(Properties options) {
|
||||||
_options = options;
|
if (!_options.isEmpty())
|
||||||
|
throw new IllegalStateException();
|
||||||
|
_options.putAll(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if was already read in
|
||||||
|
*/
|
||||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||||
|
if (_transportStyle != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
_cost = (int) DataHelper.readLong(in, 1);
|
_cost = (int) DataHelper.readLong(in, 1);
|
||||||
_expiration = DataHelper.readDate(in);
|
_expiration = DataHelper.readDate(in);
|
||||||
_transportStyle = DataHelper.readString(in);
|
_transportStyle = DataHelper.readString(in);
|
||||||
@ -115,11 +155,11 @@ public class RouterAddress extends DataStructureImpl {
|
|||||||
_transportStyle = "SSU";
|
_transportStyle = "SSU";
|
||||||
else if (_transportStyle.equals("NTCP"))
|
else if (_transportStyle.equals("NTCP"))
|
||||||
_transportStyle = "NTCP";
|
_transportStyle = "NTCP";
|
||||||
_options = DataHelper.readProperties(in);
|
DataHelper.readProperties(in, _options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||||
if ((_cost < 0) || (_transportStyle == null) || (_options == null))
|
if ((_cost < 0) || (_transportStyle == null))
|
||||||
throw new DataFormatException("Not enough data to write a router address");
|
throw new DataFormatException("Not enough data to write a router address");
|
||||||
DataHelper.writeLong(out, 1, _cost);
|
DataHelper.writeLong(out, 1, _cost);
|
||||||
DataHelper.writeDate(out, _expiration);
|
DataHelper.writeDate(out, _expiration);
|
||||||
@ -131,11 +171,12 @@ public class RouterAddress extends DataStructureImpl {
|
|||||||
public boolean equals(Object object) {
|
public boolean equals(Object object) {
|
||||||
if ((object == null) || !(object instanceof RouterAddress)) return false;
|
if ((object == null) || !(object instanceof RouterAddress)) return false;
|
||||||
RouterAddress addr = (RouterAddress) object;
|
RouterAddress addr = (RouterAddress) object;
|
||||||
|
// let's keep this fast as we are putting an address into the RouterInfo set frequently
|
||||||
return
|
return
|
||||||
_cost == addr._cost &&
|
_cost == addr._cost &&
|
||||||
DataHelper.eq(_transportStyle, addr._transportStyle) &&
|
DataHelper.eq(_transportStyle, addr._transportStyle);
|
||||||
DataHelper.eq(_options, addr._options) &&
|
//DataHelper.eq(_options, addr._options) &&
|
||||||
DataHelper.eq(_expiration, addr._expiration);
|
//DataHelper.eq(_expiration, addr._expiration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,9 +202,7 @@ public class RouterAddress extends DataStructureImpl {
|
|||||||
buf.append("\n\tExpiration: ").append(_expiration);
|
buf.append("\n\tExpiration: ").append(_expiration);
|
||||||
if (_options != null) {
|
if (_options != null) {
|
||||||
buf.append("\n\tOptions: #: ").append(_options.size());
|
buf.append("\n\tOptions: #: ").append(_options.size());
|
||||||
Properties p = new OrderedProperties();
|
for (Map.Entry e : _options.entrySet()) {
|
||||||
p.putAll(_options);
|
|
||||||
for (Map.Entry e : p.entrySet()) {
|
|
||||||
String key = (String) e.getKey();
|
String key = (String) e.getKey();
|
||||||
String val = (String) e.getValue();
|
String val = (String) e.getValue();
|
||||||
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
|
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
|
||||||
|
@ -19,6 +19,7 @@ import java.util.Date;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
@ -32,6 +33,13 @@ import net.i2p.util.OrderedProperties;
|
|||||||
* Defines the data that a router either publishes to the global routing table or
|
* Defines the data that a router either publishes to the global routing table or
|
||||||
* provides to trusted peers.
|
* provides to trusted peers.
|
||||||
*
|
*
|
||||||
|
* For efficiency, the methods and structures here are now unsynchronized.
|
||||||
|
* Initialize the RI with readBytes(), or call the setters and then sign() in a single thread.
|
||||||
|
* Don't change it after that.
|
||||||
|
*
|
||||||
|
* To ensure integrity of the RouterInfo, methods that change an element of the
|
||||||
|
* RouterInfo will throw an IllegalStateException after the RouterInfo is signed.
|
||||||
|
*
|
||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class RouterInfo extends DatabaseEntry {
|
public class RouterInfo extends DatabaseEntry {
|
||||||
@ -41,7 +49,7 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
private final Set<RouterAddress> _addresses;
|
private final Set<RouterAddress> _addresses;
|
||||||
/** may be null to save memory, no longer final */
|
/** may be null to save memory, no longer final */
|
||||||
private Set<Hash> _peers;
|
private Set<Hash> _peers;
|
||||||
private /* FIXME final FIXME */ Properties _options;
|
private final Properties _options;
|
||||||
private volatile boolean _validated;
|
private volatile boolean _validated;
|
||||||
private volatile boolean _isValid;
|
private volatile boolean _isValid;
|
||||||
private volatile String _stringified;
|
private volatile String _stringified;
|
||||||
@ -67,14 +75,19 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
_options = new OrderedProperties();
|
_options = new OrderedProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used only by Router and PublishLocalRouterInfoJob.
|
||||||
|
* Copies ONLY the identity and peers.
|
||||||
|
* Does not copy published, addresses, options, or signature.
|
||||||
|
*/
|
||||||
public RouterInfo(RouterInfo old) {
|
public RouterInfo(RouterInfo old) {
|
||||||
this();
|
this();
|
||||||
setIdentity(old.getIdentity());
|
setIdentity(old.getIdentity());
|
||||||
setPublished(old.getPublished());
|
//setPublished(old.getPublished());
|
||||||
setAddresses(old.getAddresses());
|
//setAddresses(old.getAddresses());
|
||||||
setPeers(old.getPeers());
|
setPeers(old.getPeers());
|
||||||
setOptions(old.getOptions());
|
//setOptions(old.getOptions());
|
||||||
setSignature(old.getSignature());
|
//setSignature(old.getSignature());
|
||||||
// copy over _byteified?
|
// copy over _byteified?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,12 +103,6 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
return KEY_TYPE_ROUTERINFO;
|
return KEY_TYPE_ROUTERINFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetCache() {
|
|
||||||
_stringified = null;
|
|
||||||
_byteified = null;
|
|
||||||
_hashCodeInitialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the identity of the router represented
|
* Retrieve the identity of the router represented
|
||||||
*
|
*
|
||||||
@ -107,10 +114,12 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
/**
|
/**
|
||||||
* Configure the identity of the router represented
|
* Configure the identity of the router represented
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
*/
|
*/
|
||||||
public void setIdentity(RouterIdentity ident) {
|
public void setIdentity(RouterIdentity ident) {
|
||||||
|
if (_signature != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
_identity = ident;
|
_identity = ident;
|
||||||
resetCache();
|
|
||||||
// We only want to cache the bytes for our own RI, which is frequently written.
|
// We only want to cache the bytes for our own RI, which is frequently written.
|
||||||
// To cache for all RIs doubles the RI memory usage.
|
// To cache for all RIs doubles the RI memory usage.
|
||||||
// setIdentity() is only called when we are creating our own RI.
|
// setIdentity() is only called when we are creating our own RI.
|
||||||
@ -133,34 +142,35 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
/**
|
/**
|
||||||
* Date on which it was published, in milliseconds since Midnight GMT on Jan 01, 1970
|
* Date on which it was published, in milliseconds since Midnight GMT on Jan 01, 1970
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
*/
|
*/
|
||||||
public void setPublished(long published) {
|
public void setPublished(long published) {
|
||||||
|
if (_signature != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
_published = published;
|
_published = published;
|
||||||
resetCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the set of RouterAddress structures at which this
|
* Retrieve the set of RouterAddress structures at which this
|
||||||
* router can be contacted.
|
* router can be contacted.
|
||||||
*
|
*
|
||||||
|
* @return unmodifiable view, non-null
|
||||||
*/
|
*/
|
||||||
public Set<RouterAddress> getAddresses() {
|
public Set<RouterAddress> getAddresses() {
|
||||||
synchronized (_addresses) {
|
return Collections.unmodifiableSet(_addresses);
|
||||||
return new HashSet(_addresses);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify a set of RouterAddress structures at which this router
|
* Specify a set of RouterAddress structures at which this router
|
||||||
* can be contacted.
|
* can be contacted.
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
*/
|
*/
|
||||||
public void setAddresses(Set<RouterAddress> addresses) {
|
public void setAddresses(Set<RouterAddress> addresses) {
|
||||||
synchronized (_addresses) {
|
if (_signature != null)
|
||||||
_addresses.clear();
|
throw new IllegalStateException();
|
||||||
if (addresses != null) _addresses.addAll(addresses);
|
_addresses.clear();
|
||||||
}
|
if (addresses != null) _addresses.addAll(addresses);
|
||||||
resetCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,8 +190,11 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
* this router can be reached through.
|
* this router can be reached through.
|
||||||
*
|
*
|
||||||
* @deprecated Implemented here but unused elsewhere
|
* @deprecated Implemented here but unused elsewhere
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
*/
|
*/
|
||||||
public void setPeers(Set<Hash> peers) {
|
public void setPeers(Set<Hash> peers) {
|
||||||
|
if (_signature != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
if (peers == null || peers.isEmpty()) {
|
if (peers == null || peers.isEmpty()) {
|
||||||
_peers = null;
|
_peers = null;
|
||||||
return;
|
return;
|
||||||
@ -192,37 +205,46 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
_peers.clear();
|
_peers.clear();
|
||||||
_peers.addAll(peers);
|
_peers.addAll(peers);
|
||||||
}
|
}
|
||||||
resetCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a set of options or statistics that the router can expose
|
* Retrieve a set of options or statistics that the router can expose.
|
||||||
*
|
*
|
||||||
|
* @deprecated use getOptionsMap()
|
||||||
|
* @return sorted, non-null, NOT a copy, do not modify!!!
|
||||||
*/
|
*/
|
||||||
public Properties getOptions() {
|
public Properties getOptions() {
|
||||||
if (_options == null) return new Properties();
|
return _options;
|
||||||
synchronized (_options) {
|
|
||||||
return (Properties) _options.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public String getOption(String opt) {
|
|
||||||
if (_options == null) return null;
|
|
||||||
synchronized (_options) {
|
|
||||||
return _options.getProperty(opt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure a set of options or statistics that the router can expose
|
* Retrieve a set of options or statistics that the router can expose.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable view, non-null, sorted
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
public Map getOptionsMap() {
|
||||||
|
return Collections.unmodifiableMap(_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOption(String opt) {
|
||||||
|
return _options.getProperty(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a set of options or statistics that the router can expose.
|
||||||
|
* Makes a copy.
|
||||||
|
*
|
||||||
* @param options if null, clears current options
|
* @param options if null, clears current options
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
*/
|
*/
|
||||||
public void setOptions(Properties options) {
|
public void setOptions(Properties options) {
|
||||||
synchronized (_options) {
|
if (_signature != null)
|
||||||
_options.clear();
|
throw new IllegalStateException();
|
||||||
if (options != null)
|
|
||||||
_options.putAll(options);
|
_options.clear();
|
||||||
}
|
if (options != null)
|
||||||
resetCache();
|
_options.putAll(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -234,14 +256,14 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
protected byte[] getBytes() throws DataFormatException {
|
protected byte[] getBytes() throws DataFormatException {
|
||||||
if (_byteified != null) return _byteified;
|
if (_byteified != null) return _byteified;
|
||||||
if (_identity == null) throw new DataFormatException("Router identity isn't set? wtf!");
|
if (_identity == null) throw new DataFormatException("Router identity isn't set? wtf!");
|
||||||
if (_addresses == null) throw new DataFormatException("Router addressess isn't set? wtf!");
|
|
||||||
if (_options == null) throw new DataFormatException("Router options isn't set? wtf!");
|
|
||||||
|
|
||||||
//long before = Clock.getInstance().now();
|
//long before = Clock.getInstance().now();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(6*1024);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(2*1024);
|
||||||
try {
|
try {
|
||||||
_identity.writeBytes(out);
|
_identity.writeBytes(out);
|
||||||
DataHelper.writeDate(out, new Date(_published));
|
// avoid thrashing objects
|
||||||
|
//DataHelper.writeDate(out, new Date(_published));
|
||||||
|
DataHelper.writeLong(out, 8, _published);
|
||||||
int sz = _addresses.size();
|
int sz = _addresses.size();
|
||||||
if (sz <= 0 || isHidden()) {
|
if (sz <= 0 || isHidden()) {
|
||||||
// Do not send IP address to peers in hidden mode
|
// Do not send IP address to peers in hidden mode
|
||||||
@ -249,11 +271,12 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
} else {
|
} else {
|
||||||
DataHelper.writeLong(out, 1, sz);
|
DataHelper.writeLong(out, 1, sz);
|
||||||
Collection<RouterAddress> addresses = _addresses;
|
Collection<RouterAddress> addresses = _addresses;
|
||||||
if (sz > 1)
|
if (sz > 1) {
|
||||||
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
||||||
// network-wide. The signature is not checked at readin time, but only
|
// network-wide. The signature is not checked at readin time, but only
|
||||||
// later, and the addresses are stored in a Set, not a List.
|
// later, and the addresses are stored in a Set, not a List.
|
||||||
addresses = (Collection<RouterAddress>) DataHelper.sortStructures(addresses);
|
addresses = (Collection<RouterAddress>) DataHelper.sortStructures(addresses);
|
||||||
|
}
|
||||||
for (RouterAddress addr : addresses) {
|
for (RouterAddress addr : addresses) {
|
||||||
addr.writeBytes(out);
|
addr.writeBytes(out);
|
||||||
}
|
}
|
||||||
@ -293,7 +316,7 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
* Determine whether this router info is authorized with a valid signature
|
* Determine whether this router info is authorized with a valid signature
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public synchronized boolean isValid() {
|
public boolean isValid() {
|
||||||
if (!_validated) doValidate();
|
if (!_validated) doValidate();
|
||||||
return _isValid;
|
return _isValid;
|
||||||
}
|
}
|
||||||
@ -304,11 +327,7 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
* @return -1 if unknown
|
* @return -1 if unknown
|
||||||
*/
|
*/
|
||||||
public int getNetworkId() {
|
public int getNetworkId() {
|
||||||
if (_options == null) return -1;
|
String id = _options.getProperty(PROP_NETWORK_ID);
|
||||||
String id = null;
|
|
||||||
synchronized (_options) {
|
|
||||||
id = _options.getProperty(PROP_NETWORK_ID);
|
|
||||||
}
|
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt(id);
|
return Integer.parseInt(id);
|
||||||
@ -322,11 +341,7 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
* @return non-null, empty string if none
|
* @return non-null, empty string if none
|
||||||
*/
|
*/
|
||||||
public String getCapabilities() {
|
public String getCapabilities() {
|
||||||
if (_options == null) return "";
|
String capabilities = _options.getProperty(PROP_CAPABILITIES);
|
||||||
String capabilities = null;
|
|
||||||
synchronized (_options) {
|
|
||||||
capabilities = _options.getProperty(PROP_CAPABILITIES);
|
|
||||||
}
|
|
||||||
if (capabilities != null)
|
if (capabilities != null)
|
||||||
return capabilities;
|
return capabilities;
|
||||||
else
|
else
|
||||||
@ -358,20 +373,27 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
return (bwTier);
|
return (bwTier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
|
*/
|
||||||
public void addCapability(char cap) {
|
public void addCapability(char cap) {
|
||||||
if (_options == null) _options = new OrderedProperties();
|
if (_signature != null)
|
||||||
synchronized (_options) {
|
throw new IllegalStateException();
|
||||||
|
|
||||||
String caps = _options.getProperty(PROP_CAPABILITIES);
|
String caps = _options.getProperty(PROP_CAPABILITIES);
|
||||||
if (caps == null)
|
if (caps == null)
|
||||||
_options.setProperty(PROP_CAPABILITIES, ""+cap);
|
_options.setProperty(PROP_CAPABILITIES, ""+cap);
|
||||||
else if (caps.indexOf(cap) == -1)
|
else if (caps.indexOf(cap) == -1)
|
||||||
_options.setProperty(PROP_CAPABILITIES, caps + cap);
|
_options.setProperty(PROP_CAPABILITIES, caps + cap);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if RouterInfo is already signed
|
||||||
|
*/
|
||||||
public void delCapability(char cap) {
|
public void delCapability(char cap) {
|
||||||
if (_options == null) return;
|
if (_signature != null)
|
||||||
synchronized (_options) {
|
throw new IllegalStateException();
|
||||||
|
|
||||||
String caps = _options.getProperty(PROP_CAPABILITIES);
|
String caps = _options.getProperty(PROP_CAPABILITIES);
|
||||||
int idx;
|
int idx;
|
||||||
if (caps == null) {
|
if (caps == null) {
|
||||||
@ -384,7 +406,6 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
buf.deleteCharAt(idx);
|
buf.deleteCharAt(idx);
|
||||||
_options.setProperty(PROP_CAPABILITIES, buf.toString());
|
_options.setProperty(PROP_CAPABILITIES, buf.toString());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -409,12 +430,9 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public RouterAddress getTargetAddress(String transportStyle) {
|
public RouterAddress getTargetAddress(String transportStyle) {
|
||||||
synchronized (_addresses) {
|
for (RouterAddress addr : _addresses) {
|
||||||
for (Iterator iter = _addresses.iterator(); iter.hasNext(); ) {
|
if (addr.getTransportStyle().equals(transportStyle))
|
||||||
RouterAddress addr = (RouterAddress)iter.next();
|
return addr;
|
||||||
if (addr.getTransportStyle().equals(transportStyle))
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -425,12 +443,9 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
*/
|
*/
|
||||||
public List<RouterAddress> getTargetAddresses(String transportStyle) {
|
public List<RouterAddress> getTargetAddresses(String transportStyle) {
|
||||||
List<RouterAddress> ret = new Vector<RouterAddress>();
|
List<RouterAddress> ret = new Vector<RouterAddress>();
|
||||||
synchronized(this._addresses) {
|
for (RouterAddress addr : _addresses) {
|
||||||
for(Object o : this._addresses) {
|
if(addr.getTransportStyle().equals(transportStyle))
|
||||||
RouterAddress addr = (RouterAddress)o;
|
ret.add(addr);
|
||||||
if(addr.getTransportStyle().equals(transportStyle))
|
|
||||||
ret.add(addr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -438,9 +453,9 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
/**
|
/**
|
||||||
* Actually validate the signature
|
* Actually validate the signature
|
||||||
*/
|
*/
|
||||||
private synchronized void doValidate() {
|
private void doValidate() {
|
||||||
_validated = true;
|
|
||||||
_isValid = super.verifySignature();
|
_isValid = super.verifySignature();
|
||||||
|
_validated = true;
|
||||||
|
|
||||||
if (!_isValid) {
|
if (!_isValid) {
|
||||||
byte data[] = null;
|
byte data[] = null;
|
||||||
@ -459,15 +474,21 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This does NOT validate the signature
|
* This does NOT validate the signature
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if RouterInfo was already read in
|
||||||
*/
|
*/
|
||||||
public synchronized void readBytes(InputStream in) throws DataFormatException, IOException {
|
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||||
|
if (_signature != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
_identity = new RouterIdentity();
|
_identity = new RouterIdentity();
|
||||||
_identity.readBytes(in);
|
_identity.readBytes(in);
|
||||||
Date when = DataHelper.readDate(in);
|
// avoid thrashing objects
|
||||||
if (when == null)
|
//Date when = DataHelper.readDate(in);
|
||||||
_published = 0;
|
//if (when == null)
|
||||||
else
|
// _published = 0;
|
||||||
_published = when.getTime();
|
//else
|
||||||
|
// _published = when.getTime();
|
||||||
|
_published = DataHelper.readLong(in, 8);
|
||||||
int numAddresses = (int) DataHelper.readLong(in, 1);
|
int numAddresses = (int) DataHelper.readLong(in, 1);
|
||||||
for (int i = 0; i < numAddresses; i++) {
|
for (int i = 0; i < numAddresses; i++) {
|
||||||
RouterAddress address = new RouterAddress();
|
RouterAddress address = new RouterAddress();
|
||||||
@ -485,11 +506,10 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
_peers.add(peerIdentityHash);
|
_peers.add(peerIdentityHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_options = DataHelper.readProperties(in);
|
DataHelper.readProperties(in, _options);
|
||||||
_signature = new Signature();
|
_signature = new Signature();
|
||||||
_signature.readBytes(in);
|
_signature.readBytes(in);
|
||||||
|
|
||||||
resetCache();
|
|
||||||
|
|
||||||
//_log.debug("Read routerInfo: " + toString());
|
//_log.debug("Read routerInfo: " + toString());
|
||||||
}
|
}
|
||||||
@ -497,13 +517,13 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
/**
|
/**
|
||||||
* This does NOT validate the signature
|
* This does NOT validate the signature
|
||||||
*/
|
*/
|
||||||
public synchronized void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||||
if (_identity == null) throw new DataFormatException("Missing identity");
|
if (_identity == null) throw new DataFormatException("Missing identity");
|
||||||
if (_published < 0) throw new DataFormatException("Invalid published date: " + _published);
|
if (_published < 0) throw new DataFormatException("Invalid published date: " + _published);
|
||||||
if (_signature == null) throw new DataFormatException("Signature is null");
|
if (_signature == null) throw new DataFormatException("Signature is null");
|
||||||
//if (!isValid())
|
//if (!isValid())
|
||||||
// throw new DataFormatException("Data is not valid");
|
// throw new DataFormatException("Data is not valid");
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
|
||||||
baos.write(getBytes());
|
baos.write(getBytes());
|
||||||
_signature.writeBytes(baos);
|
_signature.writeBytes(baos);
|
||||||
|
|
||||||
@ -518,10 +538,11 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
RouterInfo info = (RouterInfo) object;
|
RouterInfo info = (RouterInfo) object;
|
||||||
return DataHelper.eq(_identity, info.getIdentity())
|
return DataHelper.eq(_identity, info.getIdentity())
|
||||||
&& DataHelper.eq(_signature, info.getSignature())
|
&& DataHelper.eq(_signature, info.getSignature())
|
||||||
&& _published == info.getPublished()
|
&& _published == info.getPublished();
|
||||||
&& DataHelper.eq(_addresses, info.getAddresses())
|
// Let's speed up the NetDB
|
||||||
&& DataHelper.eq(_options, info.getOptions())
|
//&& DataHelper.eq(_addresses, info.getAddresses())
|
||||||
&& DataHelper.eq(getPeers(), info.getPeers());
|
//&& DataHelper.eq(_options, info.getOptions())
|
||||||
|
//&& DataHelper.eq(getPeers(), info.getPeers());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -541,23 +562,19 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
buf.append("\n\tIdentity: ").append(_identity);
|
buf.append("\n\tIdentity: ").append(_identity);
|
||||||
buf.append("\n\tSignature: ").append(_signature);
|
buf.append("\n\tSignature: ").append(_signature);
|
||||||
buf.append("\n\tPublished on: ").append(new Date(_published));
|
buf.append("\n\tPublished on: ").append(new Date(_published));
|
||||||
Set addresses = _addresses; // getAddresses()
|
buf.append("\n\tAddresses: #: ").append(_addresses.size());
|
||||||
buf.append("\n\tAddresses: #: ").append(addresses.size());
|
for (RouterAddress addr : _addresses) {
|
||||||
for (Iterator iter = addresses.iterator(); iter.hasNext();) {
|
|
||||||
RouterAddress addr = (RouterAddress) iter.next();
|
|
||||||
buf.append("\n\t\tAddress: ").append(addr);
|
buf.append("\n\t\tAddress: ").append(addr);
|
||||||
}
|
}
|
||||||
Set peers = getPeers();
|
Set<Hash> peers = getPeers();
|
||||||
buf.append("\n\tPeers: #: ").append(peers.size());
|
buf.append("\n\tPeers: #: ").append(peers.size());
|
||||||
for (Iterator iter = peers.iterator(); iter.hasNext();) {
|
for (Hash hash : peers) {
|
||||||
Hash hash = (Hash) iter.next();
|
|
||||||
buf.append("\n\t\tPeer hash: ").append(hash);
|
buf.append("\n\t\tPeer hash: ").append(hash);
|
||||||
}
|
}
|
||||||
Properties options = _options; // getOptions();
|
buf.append("\n\tOptions: #: ").append(_options.size());
|
||||||
buf.append("\n\tOptions: #: ").append(options.size());
|
for (Map.Entry e : _options.entrySet()) {
|
||||||
for (Iterator iter = options.keySet().iterator(); iter.hasNext();) {
|
String key = (String) e.getKey();
|
||||||
String key = (String) iter.next();
|
String val = (String) e.getValue();
|
||||||
String val = options.getProperty(key);
|
|
||||||
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
|
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
|
||||||
}
|
}
|
||||||
buf.append("]");
|
buf.append("]");
|
||||||
|
@ -488,9 +488,7 @@ public class Blocklist {
|
|||||||
for (int j = 0; j < paddr.size(); j++) {
|
for (int j = 0; j < paddr.size(); j++) {
|
||||||
RouterAddress pa = (RouterAddress) pladdr.get(j);
|
RouterAddress pa = (RouterAddress) pladdr.get(j);
|
||||||
if (pa == null) continue;
|
if (pa == null) continue;
|
||||||
Properties pprops = pa.getOptions();
|
String phost = pa.getOption("host");
|
||||||
if (pprops == null) continue;
|
|
||||||
String phost = pprops.getProperty("host");
|
|
||||||
if (phost == null) continue;
|
if (phost == null) continue;
|
||||||
if (oldphost != null && oldphost.equals(phost)) continue;
|
if (oldphost != null && oldphost.equals(phost)) continue;
|
||||||
oldphost = phost;
|
oldphost = phost;
|
||||||
|
@ -60,7 +60,7 @@ import net.i2p.util.SimpleScheduler;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Router implements RouterClock.ClockShiftListener {
|
public class Router implements RouterClock.ClockShiftListener {
|
||||||
private final Log _log;
|
private Log _log;
|
||||||
private final RouterContext _context;
|
private final RouterContext _context;
|
||||||
private final Map<String, String> _config;
|
private final Map<String, String> _config;
|
||||||
/** full path */
|
/** full path */
|
||||||
@ -77,9 +77,9 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
private ShutdownHook _shutdownHook;
|
private ShutdownHook _shutdownHook;
|
||||||
/** non-cancellable shutdown has begun */
|
/** non-cancellable shutdown has begun */
|
||||||
private volatile boolean _shutdownInProgress;
|
private volatile boolean _shutdownInProgress;
|
||||||
private final I2PThread _gracefulShutdownDetector;
|
private I2PThread _gracefulShutdownDetector;
|
||||||
private final RouterWatchdog _watchdog;
|
private RouterWatchdog _watchdog;
|
||||||
private final Thread _watchdogThread;
|
private Thread _watchdogThread;
|
||||||
|
|
||||||
public final static String PROP_CONFIG_FILE = "router.configLocation";
|
public final static String PROP_CONFIG_FILE = "router.configLocation";
|
||||||
|
|
||||||
@ -128,9 +128,17 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
System.setProperty("Dorg.mortbay.util.FileResource.checkAliases", "true");
|
System.setProperty("Dorg.mortbay.util.FileResource.checkAliases", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiation only. Starts no threads. Does not install updates.
|
||||||
|
* RouterContext is created but not initialized.
|
||||||
|
* You must call runRouter() after any constructor to start things up.
|
||||||
|
*/
|
||||||
public Router() { this(null, null); }
|
public Router() { this(null, null); }
|
||||||
|
|
||||||
public Router(Properties envProps) { this(null, envProps); }
|
public Router(Properties envProps) { this(null, envProps); }
|
||||||
|
|
||||||
public Router(String configFilename) { this(configFilename, null); }
|
public Router(String configFilename) { this(configFilename, null); }
|
||||||
|
|
||||||
public Router(String configFilename, Properties envProps) {
|
public Router(String configFilename, Properties envProps) {
|
||||||
_gracefulExitCode = -1;
|
_gracefulExitCode = -1;
|
||||||
_config = new ConcurrentHashMap();
|
_config = new ConcurrentHashMap();
|
||||||
@ -235,14 +243,16 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
_config.put("router.updateLastInstalled", now);
|
_config.put("router.updateLastInstalled", now);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
// ********* Start no threads before here ********* //
|
||||||
|
}
|
||||||
|
|
||||||
// This is here so that we can get the directory location from the context
|
/**
|
||||||
// for the zip file and the base location to unzip to.
|
* Initializes the RouterContext.
|
||||||
// If it does an update, it never returns.
|
* Starts some threads. Does not install updates.
|
||||||
// I guess it's better to have the other-router check above this, we don't want to
|
* All this was in the constructor.
|
||||||
// overwrite an existing running router's jar files. Other than ours.
|
* @since 0.8.12
|
||||||
installUpdates();
|
*/
|
||||||
|
private void startupStuff() {
|
||||||
// ********* Start no threads before here ********* //
|
// ********* Start no threads before here ********* //
|
||||||
//
|
//
|
||||||
// NOW we can start the ping file thread.
|
// NOW we can start the ping file thread.
|
||||||
@ -372,7 +382,14 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
|
|
||||||
public RouterContext getContext() { return _context; }
|
public RouterContext getContext() { return _context; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the RouterContext.
|
||||||
|
* Starts the threads. Does not install updates.
|
||||||
|
*/
|
||||||
void runRouter() {
|
void runRouter() {
|
||||||
|
if (_isAlive)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
startupStuff();
|
||||||
_isAlive = true;
|
_isAlive = true;
|
||||||
_started = _context.clock().now();
|
_started = _context.clock().now();
|
||||||
try {
|
try {
|
||||||
@ -1266,13 +1283,18 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
System.out.println("Starting I2P " + RouterVersion.FULL_VERSION);
|
System.out.println("Starting I2P " + RouterVersion.FULL_VERSION);
|
||||||
// installUpdates() moved to constructor so we can get file locations from the context
|
|
||||||
// installUpdates();
|
|
||||||
//verifyWrapperConfig();
|
//verifyWrapperConfig();
|
||||||
Router r = new Router();
|
Router r = new Router();
|
||||||
if ( (args != null) && (args.length == 1) && ("rebuild".equals(args[0])) ) {
|
if ( (args != null) && (args.length == 1) && ("rebuild".equals(args[0])) ) {
|
||||||
r.rebuildNewIdentity();
|
r.rebuildNewIdentity();
|
||||||
} else {
|
} else {
|
||||||
|
// This is here so that we can get the directory location from the context
|
||||||
|
// for the zip file and the base location to unzip to.
|
||||||
|
// If it does an update, it never returns.
|
||||||
|
// I guess it's better to have the other-router check above this, we don't want to
|
||||||
|
// overwrite an existing running router's jar files. Other than ours.
|
||||||
|
r.installUpdates();
|
||||||
|
// ********* Start no threads before here ********* //
|
||||||
r.runRouter();
|
r.runRouter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1281,6 +1303,7 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
private static final String DELETE_FILE = "deletelist.txt";
|
private static final String DELETE_FILE = "deletelist.txt";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Context must be available.
|
||||||
* Unzip update file found in the router dir OR base dir, to the base dir
|
* Unzip update file found in the router dir OR base dir, to the base dir
|
||||||
*
|
*
|
||||||
* If we can't write to the base dir, complain.
|
* If we can't write to the base dir, complain.
|
||||||
|
@ -41,7 +41,7 @@ public class PublishLocalRouterInfoJob extends JobImpl {
|
|||||||
RouterInfo ri = new RouterInfo(getContext().router().getRouterInfo());
|
RouterInfo ri = new RouterInfo(getContext().router().getRouterInfo());
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Old routerInfo contains " + ri.getAddresses().size()
|
_log.debug("Old routerInfo contains " + ri.getAddresses().size()
|
||||||
+ " addresses and " + ri.getOptions().size() + " options");
|
+ " addresses and " + ri.getOptionsMap().size() + " options");
|
||||||
Properties stats = getContext().statPublisher().publishStatistics();
|
Properties stats = getContext().statPublisher().publishStatistics();
|
||||||
stats.setProperty(RouterInfo.PROP_NETWORK_ID, ""+Router.NETWORK_ID);
|
stats.setProperty(RouterInfo.PROP_NETWORK_ID, ""+Router.NETWORK_ID);
|
||||||
try {
|
try {
|
||||||
@ -60,7 +60,7 @@ public class PublishLocalRouterInfoJob extends JobImpl {
|
|||||||
getContext().router().setRouterInfo(ri);
|
getContext().router().setRouterInfo(ri);
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Newly updated routerInfo is published with " + stats.size()
|
_log.info("Newly updated routerInfo is published with " + stats.size()
|
||||||
+ "/" + ri.getOptions().size() + " options on "
|
+ "/" + ri.getOptionsMap().size() + " options on "
|
||||||
+ new Date(ri.getPublished()));
|
+ new Date(ri.getPublished()));
|
||||||
try {
|
try {
|
||||||
getContext().netDb().publish(ri);
|
getContext().netDb().publish(ri);
|
||||||
|
@ -133,8 +133,7 @@ class FloodfillMonitorJob extends JobImpl {
|
|||||||
if (ra == null)
|
if (ra == null)
|
||||||
happy = false;
|
happy = false;
|
||||||
else {
|
else {
|
||||||
Properties props = ra.getOptions();
|
if (ra.getOption("ihost0") != null)
|
||||||
if (props == null || props.getProperty("ihost0") != null)
|
|
||||||
happy = false;
|
happy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -786,8 +786,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
|||||||
RouterAddress ra = routerInfo.getTargetAddress("SSU");
|
RouterAddress ra = routerInfo.getTargetAddress("SSU");
|
||||||
if (ra != null) {
|
if (ra != null) {
|
||||||
// Introducers change often, introducee will ping introducer for 2 hours
|
// Introducers change often, introducee will ping introducer for 2 hours
|
||||||
Properties props = ra.getOptions();
|
if (ra.getOption("ihost0") != null)
|
||||||
if (props != null && props.getProperty("ihost0") != null)
|
|
||||||
return "Peer " + key.toBase64() + " published > 75m ago with SSU Introducers";
|
return "Peer " + key.toBase64() + " published > 75m ago with SSU Introducers";
|
||||||
if (routerInfo.getTargetAddress("NTCP") == null)
|
if (routerInfo.getTargetAddress("NTCP") == null)
|
||||||
return "Peer " + key.toBase64() + " published > 75m ago, SSU only without introducers";
|
return "Peer " + key.toBase64() + " published > 75m ago, SSU only without introducers";
|
||||||
@ -822,10 +821,10 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
|||||||
if (err != null)
|
if (err != null)
|
||||||
throw new IllegalArgumentException("Invalid store attempt - " + err);
|
throw new IllegalArgumentException("Invalid store attempt - " + err);
|
||||||
|
|
||||||
//if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
// _log.debug("RouterInfo " + key.toBase64() + " is stored with "
|
_log.debug("RouterInfo " + key.toBase64() + " is stored with "
|
||||||
// + routerInfo.getOptions().size() + " options on "
|
+ routerInfo.getOptionsMap().size() + " options on "
|
||||||
// + new Date(routerInfo.getPublished()));
|
+ new Date(routerInfo.getPublished()));
|
||||||
|
|
||||||
_context.peerManager().setCapabilities(key, routerInfo.getCapabilities());
|
_context.peerManager().setCapabilities(key, routerInfo.getCapabilities());
|
||||||
_ds.put(key, routerInfo, persist);
|
_ds.put(key, routerInfo, persist);
|
||||||
|
@ -701,8 +701,7 @@ public class ProfileOrganizer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// This is the quick way of doing UDPAddress.getIntroducerCount() > 0
|
// This is the quick way of doing UDPAddress.getIntroducerCount() > 0
|
||||||
Properties props = ra.getOptions();
|
if (ra.getOption("ihost0") != null)
|
||||||
if (props != null && props.getProperty("ihost0") != null)
|
|
||||||
l.add(peer);
|
l.add(peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1263,9 +1262,7 @@ public class ProfileOrganizer {
|
|||||||
if (paddr == null)
|
if (paddr == null)
|
||||||
return rv;
|
return rv;
|
||||||
for (RouterAddress pa : paddr) {
|
for (RouterAddress pa : paddr) {
|
||||||
Properties pprops = pa.getOptions();
|
String phost = pa.getOption("host");
|
||||||
if (pprops == null) continue;
|
|
||||||
String phost = pprops.getProperty("host");
|
|
||||||
if (phost == null) continue;
|
if (phost == null) continue;
|
||||||
InetAddress pi;
|
InetAddress pi;
|
||||||
try {
|
try {
|
||||||
|
@ -343,15 +343,12 @@ public class TransportManager implements TransportEventListener {
|
|||||||
for (Transport t : _transports.values()) {
|
for (Transport t : _transports.values()) {
|
||||||
int port = t.getRequestedPort();
|
int port = t.getRequestedPort();
|
||||||
if (t.getCurrentAddress() != null) {
|
if (t.getCurrentAddress() != null) {
|
||||||
Properties opts = t.getCurrentAddress().getOptions();
|
String s = t.getCurrentAddress().getOption("port");
|
||||||
if (opts != null) {
|
|
||||||
String s = opts.getProperty("port");
|
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
try {
|
try {
|
||||||
port = Integer.parseInt(s);
|
port = Integer.parseInt(s);
|
||||||
} catch (NumberFormatException nfe) {}
|
} catch (NumberFormatException nfe) {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Use UDP port for NTCP too - see comment in NTCPTransport.getRequestedPort() for why this is here
|
// Use UDP port for NTCP too - see comment in NTCPTransport.getRequestedPort() for why this is here
|
||||||
if (t.getStyle().equals(NTCPTransport.STYLE) && port <= 0 &&
|
if (t.getStyle().equals(NTCPTransport.STYLE) && port <= 0 &&
|
||||||
|
@ -57,13 +57,13 @@ public class NTCPAddress {
|
|||||||
_port = -1;
|
_port = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String host = addr.getOptions().getProperty(PROP_HOST);
|
String host = addr.getOption(PROP_HOST);
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
_host = null;
|
_host = null;
|
||||||
_port = -1;
|
_port = -1;
|
||||||
} else {
|
} else {
|
||||||
_host = host.trim();
|
_host = host.trim();
|
||||||
String port = addr.getOptions().getProperty(PROP_PORT);
|
String port = addr.getOption(PROP_PORT);
|
||||||
if ( (port != null) && (port.trim().length() > 0) && !("null".equals(port)) ) {
|
if ( (port != null) && (port.trim().length() > 0) && !("null".equals(port)) ) {
|
||||||
try {
|
try {
|
||||||
_port = Integer.parseInt(port.trim());
|
_port = Integer.parseInt(port.trim());
|
||||||
@ -156,9 +156,7 @@ public class NTCPAddress {
|
|||||||
|
|
||||||
public boolean equals(RouterAddress addr) {
|
public boolean equals(RouterAddress addr) {
|
||||||
if (addr == null) return false;
|
if (addr == null) return false;
|
||||||
Properties opts = addr.getOptions();
|
return ( (_host.equals(addr.getOption(PROP_HOST))) &&
|
||||||
if (opts == null) return false;
|
(Integer.toString(_port).equals(addr.getOption(PROP_PORT))) );
|
||||||
return ( (_host.equals(opts.getProperty(PROP_HOST))) &&
|
|
||||||
(Integer.toString(_port).equals(opts.getProperty(PROP_PORT))) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,31 +64,30 @@ public class UDPAddress {
|
|||||||
|
|
||||||
private void parse(RouterAddress addr) {
|
private void parse(RouterAddress addr) {
|
||||||
if (addr == null) return;
|
if (addr == null) return;
|
||||||
Properties opts = addr.getOptions();
|
_host = addr.getOption(PROP_HOST);
|
||||||
_host = opts.getProperty(PROP_HOST);
|
|
||||||
if (_host != null) _host = _host.trim();
|
if (_host != null) _host = _host.trim();
|
||||||
try {
|
try {
|
||||||
String port = opts.getProperty(PROP_PORT);
|
String port = addr.getOption(PROP_PORT);
|
||||||
if (port != null)
|
if (port != null)
|
||||||
_port = Integer.parseInt(port);
|
_port = Integer.parseInt(port);
|
||||||
} catch (NumberFormatException nfe) {
|
} catch (NumberFormatException nfe) {
|
||||||
_port = -1;
|
_port = -1;
|
||||||
}
|
}
|
||||||
String key = opts.getProperty(PROP_INTRO_KEY);
|
String key = addr.getOption(PROP_INTRO_KEY);
|
||||||
if (key != null)
|
if (key != null)
|
||||||
_introKey = Base64.decode(key.trim());
|
_introKey = Base64.decode(key.trim());
|
||||||
|
|
||||||
for (int i = MAX_INTRODUCERS; i >= 0; i--) {
|
for (int i = MAX_INTRODUCERS; i >= 0; i--) {
|
||||||
String host = opts.getProperty(PROP_INTRO_HOST_PREFIX + i);
|
String host = addr.getOption(PROP_INTRO_HOST_PREFIX + i);
|
||||||
if (host == null) continue;
|
if (host == null) continue;
|
||||||
String port = opts.getProperty(PROP_INTRO_PORT_PREFIX + i);
|
String port = addr.getOption(PROP_INTRO_PORT_PREFIX + i);
|
||||||
if (port == null) continue;
|
if (port == null) continue;
|
||||||
String k = opts.getProperty(PROP_INTRO_KEY_PREFIX + i);
|
String k = addr.getOption(PROP_INTRO_KEY_PREFIX + i);
|
||||||
if (k == null) continue;
|
if (k == null) continue;
|
||||||
byte ikey[] = Base64.decode(k);
|
byte ikey[] = Base64.decode(k);
|
||||||
if ( (ikey == null) || (ikey.length != SessionKey.KEYSIZE_BYTES) )
|
if ( (ikey == null) || (ikey.length != SessionKey.KEYSIZE_BYTES) )
|
||||||
continue;
|
continue;
|
||||||
String t = opts.getProperty(PROP_INTRO_TAG_PREFIX + i);
|
String t = addr.getOption(PROP_INTRO_TAG_PREFIX + i);
|
||||||
if (t == null) continue;
|
if (t == null) continue;
|
||||||
int p = -1;
|
int p = -1;
|
||||||
try {
|
try {
|
||||||
|
Reference in New Issue
Block a user