forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p.zzz.test' (head f4edeaaf6cd647f4a69847a09272b54cb51ef758)
to branch 'i2p.i2p' (head 0d7e18b693718b5924035d7a6f638ff0689af589)
This commit is contained in:
@@ -27,6 +27,7 @@ public class ClientMessage {
|
||||
private SessionConfig _senderConfig;
|
||||
private Hash _destinationHash;
|
||||
private MessageId _messageId;
|
||||
private long _expiration;
|
||||
|
||||
public ClientMessage() {
|
||||
setPayload(null);
|
||||
@@ -36,6 +37,7 @@ public class ClientMessage {
|
||||
setSenderConfig(null);
|
||||
setDestinationHash(null);
|
||||
setMessageId(null);
|
||||
setExpiration(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,4 +93,12 @@ public class ClientMessage {
|
||||
*/
|
||||
public SessionConfig getSenderConfig() { return _senderConfig; }
|
||||
public void setSenderConfig(SessionConfig config) { _senderConfig = config; }
|
||||
|
||||
/**
|
||||
* Expiration requested by the client that sent the message. This will only be available
|
||||
* for locally originated messages.
|
||||
*
|
||||
*/
|
||||
public long getExpiration() { return _expiration; }
|
||||
public void setExpiration(long e) { _expiration = e; }
|
||||
}
|
||||
|
@@ -62,4 +62,5 @@ public abstract class NetworkDatabaseFacade implements Service {
|
||||
public int getKnownRouters() { return 0; }
|
||||
public int getKnownLeaseSets() { return 0; }
|
||||
public void renderRouterInfoHTML(Writer out, String s) throws IOException {}
|
||||
public void renderStatusHTML(Writer out, boolean b) throws IOException {}
|
||||
}
|
||||
|
103
router/java/src/net/i2p/router/PersistentKeyRing.java
Normal file
103
router/java/src/net/i2p/router/PersistentKeyRing.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package net.i2p.router;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.router.TunnelPoolSettings;
|
||||
import net.i2p.util.KeyRing;
|
||||
|
||||
/**
|
||||
* ConcurrentHashMap with backing in the router.config file.
|
||||
* router.keyring.key.{base64 hash, with = replaced with $}={base64 session key}
|
||||
* Caution - not all HashMap methods are overridden.
|
||||
*/
|
||||
public class PersistentKeyRing extends KeyRing {
|
||||
private RouterContext _ctx;
|
||||
private static final String PROP_PFX = "router.keyring.key.";
|
||||
|
||||
public PersistentKeyRing(RouterContext ctx) {
|
||||
super();
|
||||
_ctx = ctx;
|
||||
addFromProperties();
|
||||
}
|
||||
|
||||
public SessionKey put(Hash h, SessionKey sk) {
|
||||
SessionKey old = super.put(h, sk);
|
||||
if (!sk.equals(old)) {
|
||||
_ctx.router().setConfigSetting(PROP_PFX + h.toBase64().replace("=", "$"),
|
||||
sk.toBase64());
|
||||
_ctx.router().saveConfig();
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
public SessionKey remove(Hash h) {
|
||||
_ctx.router().removeConfigSetting(PROP_PFX + h.toBase64().replace("=", "$"));
|
||||
_ctx.router().saveConfig();
|
||||
return super.remove(h);
|
||||
}
|
||||
|
||||
private void addFromProperties() {
|
||||
for (Iterator iter = _ctx.getPropertyNames().iterator(); iter.hasNext(); ) {
|
||||
String prop = (String) iter.next();
|
||||
if (!prop.startsWith(PROP_PFX))
|
||||
continue;
|
||||
String key = _ctx.getProperty(prop);
|
||||
if (key == null || key.length() != 44)
|
||||
continue;
|
||||
String hb = prop.substring(PROP_PFX.length());
|
||||
hb.replace("$", "=");
|
||||
Hash dest = new Hash();
|
||||
SessionKey sk = new SessionKey();
|
||||
try {
|
||||
dest.fromBase64(hb);
|
||||
sk.fromBase64(key);
|
||||
super.put(dest, sk);
|
||||
} catch (DataFormatException dfe) { continue; }
|
||||
}
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
buf.append("\n<table border=\"1\"><tr><th align=\"left\">Destination Hash<th align=\"left\">Name or Dest.<th align=\"left\">Session Key</tr>");
|
||||
for (Entry<Hash, SessionKey> e : entrySet()) {
|
||||
buf.append("\n<tr><td>");
|
||||
Hash h = e.getKey();
|
||||
buf.append(h.toBase64().substring(0, 6)).append("...");
|
||||
buf.append("<td>");
|
||||
LeaseSet ls = _ctx.netDb().lookupLeaseSetLocally(h);
|
||||
if (ls != null) {
|
||||
Destination dest = ls.getDestination();
|
||||
if (_ctx.clientManager().isLocal(dest)) {
|
||||
TunnelPoolSettings in = _ctx.tunnelManager().getInboundSettings(h);
|
||||
if (in != null && in.getDestinationNickname() != null)
|
||||
buf.append(in.getDestinationNickname());
|
||||
else
|
||||
buf.append(dest.toBase64().substring(0, 6)).append("...");
|
||||
} else {
|
||||
String host = _ctx.namingService().reverseLookup(dest);
|
||||
if (host != null)
|
||||
buf.append(host);
|
||||
else
|
||||
buf.append(dest.toBase64().substring(0, 6)).append("...");
|
||||
}
|
||||
}
|
||||
buf.append("<td>");
|
||||
SessionKey sk = e.getValue();
|
||||
buf.append(sk.toBase64());
|
||||
}
|
||||
buf.append("\n</table>\n");
|
||||
out.write(buf.toString());
|
||||
out.flush();
|
||||
}
|
||||
}
|
@@ -26,6 +26,7 @@ import net.i2p.router.transport.VMCommSystem;
|
||||
import net.i2p.router.tunnel.TunnelDispatcher;
|
||||
import net.i2p.router.tunnel.pool.TunnelPoolManager;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.KeyRing;
|
||||
|
||||
/**
|
||||
* Build off the core I2P context to provide a root for a router instance to
|
||||
@@ -366,4 +367,21 @@ public class RouterContext extends I2PAppContext {
|
||||
}
|
||||
}
|
||||
|
||||
/** override to support storage in router.config */
|
||||
@Override
|
||||
public KeyRing keyRing() {
|
||||
if (!_keyRingInitialized)
|
||||
initializeKeyRing();
|
||||
return _keyRing;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeKeyRing() {
|
||||
synchronized (this) {
|
||||
if (_keyRing == null)
|
||||
_keyRing = new PersistentKeyRing(this);
|
||||
_keyRingInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ import net.i2p.data.i2cp.I2CPMessageReader;
|
||||
import net.i2p.data.i2cp.MessageId;
|
||||
import net.i2p.data.i2cp.MessageStatusMessage;
|
||||
import net.i2p.data.i2cp.SendMessageMessage;
|
||||
import net.i2p.data.i2cp.SendMessageExpiresMessage;
|
||||
import net.i2p.data.i2cp.SessionConfig;
|
||||
import net.i2p.data.i2cp.SessionId;
|
||||
import net.i2p.router.Job;
|
||||
@@ -270,6 +271,9 @@ public class ClientConnectionRunner {
|
||||
Destination dest = message.getDestination();
|
||||
MessageId id = new MessageId();
|
||||
id.setMessageId(getNextMessageId());
|
||||
long expiration = 0;
|
||||
if (message instanceof SendMessageExpiresMessage)
|
||||
expiration = ((SendMessageExpiresMessage) message).getExpiration().getTime();
|
||||
long beforeLock = _context.clock().now();
|
||||
long inLock = 0;
|
||||
synchronized (_acceptedPending) {
|
||||
@@ -291,7 +295,7 @@ public class ClientConnectionRunner {
|
||||
// the following blocks as described above
|
||||
SessionConfig cfg = _config;
|
||||
if (cfg != null)
|
||||
_manager.distributeMessage(cfg.getDestination(), dest, payload, id);
|
||||
_manager.distributeMessage(cfg.getDestination(), dest, payload, id, expiration);
|
||||
long timeToDistribute = _context.clock().now() - beforeDistribute;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.warn("Time to distribute in the manager to "
|
||||
|
@@ -140,7 +140,7 @@ public class ClientManager {
|
||||
}
|
||||
}
|
||||
|
||||
void distributeMessage(Destination fromDest, Destination toDest, Payload payload, MessageId msgId) {
|
||||
void distributeMessage(Destination fromDest, Destination toDest, Payload payload, MessageId msgId, long expiration) {
|
||||
// check if there is a runner for it
|
||||
ClientConnectionRunner runner = getRunner(toDest);
|
||||
if (runner != null) {
|
||||
@@ -168,6 +168,7 @@ public class ClientManager {
|
||||
msg.setSenderConfig(runner.getConfig());
|
||||
msg.setFromDestination(runner.getConfig().getDestination());
|
||||
msg.setMessageId(msgId);
|
||||
msg.setExpiration(expiration);
|
||||
_ctx.clientMessagePool().add(msg, true);
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,9 @@ import net.i2p.data.i2cp.MessageId;
|
||||
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.data.i2cp.ReceiveMessageBeginMessage;
|
||||
import net.i2p.data.i2cp.ReceiveMessageEndMessage;
|
||||
import net.i2p.data.i2cp.ReconfigureSessionMessage;
|
||||
import net.i2p.data.i2cp.SendMessageMessage;
|
||||
import net.i2p.data.i2cp.SendMessageExpiresMessage;
|
||||
import net.i2p.data.i2cp.SessionId;
|
||||
import net.i2p.data.i2cp.SessionStatusMessage;
|
||||
import net.i2p.data.i2cp.SetDateMessage;
|
||||
@@ -67,6 +69,9 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
||||
case SendMessageMessage.MESSAGE_TYPE:
|
||||
handleSendMessage(reader, (SendMessageMessage)message);
|
||||
break;
|
||||
case SendMessageExpiresMessage.MESSAGE_TYPE:
|
||||
handleSendMessage(reader, (SendMessageExpiresMessage)message);
|
||||
break;
|
||||
case ReceiveMessageBeginMessage.MESSAGE_TYPE:
|
||||
handleReceiveBegin(reader, (ReceiveMessageBeginMessage)message);
|
||||
break;
|
||||
@@ -237,6 +242,17 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
||||
_context.jobQueue().addJob(new LookupDestJob(_context, _runner, message.getHash()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Message's Session ID ignored. This doesn't support removing previously set options.
|
||||
* Nor do we bother with message.getSessionConfig().verifySignature() ... should we?
|
||||
*
|
||||
*/
|
||||
private void handleReconfigureSession(I2CPMessageReader reader, ReconfigureSessionMessage message) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Updating options - session " + _runner.getSessionId());
|
||||
_runner.getConfig().getOptions().putAll(message.getSessionConfig().getOptions());
|
||||
}
|
||||
|
||||
// this *should* be mod 65536, but UnsignedInteger is still b0rked. FIXME
|
||||
private final static int MAX_SESSION_ID = 32767;
|
||||
|
||||
|
@@ -61,6 +61,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
private long _leaseSetLookupBegin;
|
||||
private TunnelInfo _outTunnel;
|
||||
private TunnelInfo _inTunnel;
|
||||
private boolean _wantACK;
|
||||
|
||||
/**
|
||||
* final timeout (in milliseconds) that the outbound message will fail in.
|
||||
@@ -69,6 +70,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
*/
|
||||
public final static String OVERALL_TIMEOUT_MS_PARAM = "clientMessageTimeout";
|
||||
private final static long OVERALL_TIMEOUT_MS_DEFAULT = 60*1000;
|
||||
private final static long OVERALL_TIMEOUT_MS_MIN = 5*1000;
|
||||
|
||||
/** priority of messages, that might get honored some day... */
|
||||
private final static int SEND_PRIORITY = 500;
|
||||
@@ -125,23 +127,34 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
_to = msg.getDestination();
|
||||
_toString = _to.calculateHash().toBase64().substring(0,4);
|
||||
_leaseSetLookupBegin = -1;
|
||||
|
||||
String param = msg.getSenderConfig().getOptions().getProperty(OVERALL_TIMEOUT_MS_PARAM);
|
||||
if (param == null)
|
||||
param = ctx.router().getConfigSetting(OVERALL_TIMEOUT_MS_PARAM);
|
||||
if (param != null) {
|
||||
try {
|
||||
timeoutMs = Long.parseLong(param);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid client message timeout specified [" + param
|
||||
+ "], defaulting to " + OVERALL_TIMEOUT_MS_DEFAULT, nfe);
|
||||
timeoutMs = OVERALL_TIMEOUT_MS_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
_start = getContext().clock().now();
|
||||
_overallExpiration = timeoutMs + _start;
|
||||
|
||||
// use expiration requested by client if available, otherwise session config,
|
||||
// otherwise router config, otherwise default
|
||||
_overallExpiration = msg.getExpiration();
|
||||
if (_overallExpiration > 0) {
|
||||
_overallExpiration = Math.max(_overallExpiration, _start + OVERALL_TIMEOUT_MS_MIN);
|
||||
_overallExpiration = Math.min(_overallExpiration, _start + OVERALL_TIMEOUT_MS_DEFAULT);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Message Expiration (ms): " + (_overallExpiration - _start));
|
||||
} else {
|
||||
String param = msg.getSenderConfig().getOptions().getProperty(OVERALL_TIMEOUT_MS_PARAM);
|
||||
if (param == null)
|
||||
param = ctx.router().getConfigSetting(OVERALL_TIMEOUT_MS_PARAM);
|
||||
if (param != null) {
|
||||
try {
|
||||
timeoutMs = Long.parseLong(param);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Invalid client message timeout specified [" + param
|
||||
+ "], defaulting to " + OVERALL_TIMEOUT_MS_DEFAULT, nfe);
|
||||
timeoutMs = OVERALL_TIMEOUT_MS_DEFAULT;
|
||||
}
|
||||
}
|
||||
_overallExpiration = timeoutMs + _start;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Default Expiration (ms): " + timeoutMs);
|
||||
}
|
||||
_finished = false;
|
||||
}
|
||||
|
||||
@@ -267,6 +280,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
long lookupTime = getContext().clock().now() - _leaseSetLookupBegin;
|
||||
getContext().statManager().addRateData("client.leaseSetFoundRemoteTime", lookupTime, lookupTime);
|
||||
}
|
||||
_wantACK = false;
|
||||
boolean ok = getNextLease();
|
||||
if (ok) {
|
||||
send();
|
||||
@@ -400,6 +414,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Added to cache - lease for " + _toString);
|
||||
_wantACK = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -443,10 +458,14 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
dieFatal();
|
||||
return;
|
||||
}
|
||||
boolean wantACK = true;
|
||||
|
||||
int existingTags = GarlicMessageBuilder.estimateAvailableTags(getContext(), _leaseSet.getEncryptionKey());
|
||||
if ( (existingTags > 30) && (getContext().random().nextInt(100) >= 5) )
|
||||
wantACK = false;
|
||||
_outTunnel = selectOutboundTunnel(_to);
|
||||
// what's the point of 5% random? possible improvements or replacements:
|
||||
// - wantACK if we changed their inbound lease (getNextLease() sets _wantACK)
|
||||
// - wantACK if we changed our outbound tunnel (selectOutboundTunnel() sets _wantACK)
|
||||
// - wantACK if we haven't in last 1m (requires a new static cache probably)
|
||||
boolean wantACK = _wantACK || existingTags <= 30 || getContext().random().nextInt(100) < 5;
|
||||
|
||||
PublicKey key = _leaseSet.getEncryptionKey();
|
||||
SessionKey sessKey = new SessionKey();
|
||||
@@ -503,7 +522,6 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
+ _lease.getTunnelId() + " on "
|
||||
+ _lease.getGateway().toBase64());
|
||||
|
||||
_outTunnel = selectOutboundTunnel(_to);
|
||||
if (_outTunnel != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getJobId() + ": Sending tunnel message out " + _outTunnel.getSendTunnelId(0) + " to "
|
||||
@@ -718,6 +736,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
_log.warn("Switching back to tunnel " + tunnel + " for " + _toString);
|
||||
_backloggedTunnelCache.remove(hashPair());
|
||||
_tunnelCache.put(hashPair(), tunnel);
|
||||
_wantACK = true;
|
||||
return tunnel;
|
||||
} // else still backlogged
|
||||
} else // no longer valid
|
||||
@@ -740,6 +759,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
tunnel = selectOutboundTunnel();
|
||||
if (tunnel != null)
|
||||
_tunnelCache.put(hashPair(), tunnel);
|
||||
_wantACK = true;
|
||||
}
|
||||
return tunnel;
|
||||
}
|
||||
|
@@ -20,12 +20,12 @@ import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Publish the local router's RouterInfo every 5 to 10 minutes
|
||||
* Publish the local router's RouterInfo periodically
|
||||
*
|
||||
*/
|
||||
public class PublishLocalRouterInfoJob extends JobImpl {
|
||||
private Log _log;
|
||||
final static long PUBLISH_DELAY = 5*60*1000; // every 5 to 10 minutes (since we randomize)
|
||||
final static long PUBLISH_DELAY = 20*60*1000;
|
||||
|
||||
public PublishLocalRouterInfoJob(RouterContext ctx) {
|
||||
super(ctx);
|
||||
@@ -67,6 +67,6 @@ public class PublishLocalRouterInfoJob extends JobImpl {
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error signing the updated local router info!", dfe);
|
||||
}
|
||||
requeue(PUBLISH_DELAY + getContext().random().nextInt((int)PUBLISH_DELAY));
|
||||
requeue((PUBLISH_DELAY/2) + getContext().random().nextInt((int)PUBLISH_DELAY));
|
||||
}
|
||||
}
|
||||
|
@@ -125,6 +125,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
private final static long ROUTER_INFO_EXPIRATION_SHORT = 90*60*1000l;
|
||||
|
||||
private final static long EXPLORE_JOB_DELAY = 10*60*1000l;
|
||||
private final static long PUBLISH_JOB_DELAY = 5*60*1000l;
|
||||
|
||||
public KademliaNetworkDatabaseFacade(RouterContext context) {
|
||||
_context = context;
|
||||
@@ -326,7 +327,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
}
|
||||
// periodically update and resign the router's 'published date', which basically
|
||||
// serves as a version
|
||||
_context.jobQueue().addJob(new PublishLocalRouterInfoJob(_context));
|
||||
Job plrij = new PublishLocalRouterInfoJob(_context);
|
||||
plrij.getTiming().setStartAfter(_context.clock().now() + PUBLISH_JOB_DELAY);
|
||||
_context.jobQueue().addJob(plrij);
|
||||
try {
|
||||
publish(ri);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
@@ -970,7 +973,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
StringBuffer buf = new StringBuffer(4*1024);
|
||||
buf.append("<h2>Network Database RouterInfo Lookup</h2>\n");
|
||||
if (".".equals(routerPrefix)) {
|
||||
renderRouterInfo(buf, _context.router().getRouterInfo(), true);
|
||||
renderRouterInfo(buf, _context.router().getRouterInfo(), true, true);
|
||||
} else {
|
||||
boolean notFound = true;
|
||||
Set routers = getRouters();
|
||||
@@ -978,7 +981,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
RouterInfo ri = (RouterInfo)iter.next();
|
||||
Hash key = ri.getIdentity().getHash();
|
||||
if (key.toBase64().startsWith(routerPrefix)) {
|
||||
renderRouterInfo(buf, ri, false);
|
||||
renderRouterInfo(buf, ri, false, true);
|
||||
notFound = false;
|
||||
}
|
||||
}
|
||||
@@ -990,7 +993,14 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
StringBuffer buf = new StringBuffer(getKnownRouters() * 2048);
|
||||
renderStatusHTML(out, true);
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out, boolean full) throws IOException {
|
||||
int size = getKnownRouters() * 512;
|
||||
if (full)
|
||||
size *= 4;
|
||||
StringBuffer buf = new StringBuffer(size);
|
||||
buf.append("<h2>Network Database Contents</h2>\n");
|
||||
if (!_initialized) {
|
||||
buf.append("<i>Not initialized</i>\n");
|
||||
@@ -1044,10 +1054,15 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
}
|
||||
|
||||
Hash us = _context.routerHash();
|
||||
out.write("<h3>Routers</h3>\n");
|
||||
out.write("<a name=\"routers\" /><h3>Routers (<a href=\"netdb.jsp");
|
||||
if (full)
|
||||
out.write("#routers\" >view without");
|
||||
else
|
||||
out.write("?f=1#routers\" >view with");
|
||||
out.write(" stats</a>)</h3>\n");
|
||||
|
||||
RouterInfo ourInfo = _context.router().getRouterInfo();
|
||||
renderRouterInfo(buf, ourInfo, true);
|
||||
renderRouterInfo(buf, ourInfo, true, true);
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
|
||||
@@ -1061,7 +1076,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
Hash key = ri.getIdentity().getHash();
|
||||
boolean isUs = key.equals(us);
|
||||
if (!isUs) {
|
||||
renderRouterInfo(buf, ri, false);
|
||||
renderRouterInfo(buf, ri, false, full);
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
String coreVersion = ri.getOption("coreVersion");
|
||||
@@ -1102,7 +1117,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private void renderRouterInfo(StringBuffer buf, RouterInfo info, boolean isUs) {
|
||||
private void renderRouterInfo(StringBuffer buf, RouterInfo info, boolean isUs, boolean full) {
|
||||
String hash = info.getIdentity().getHash().toBase64();
|
||||
buf.append("<a name=\"").append(hash.substring(0, 6)).append("\" />");
|
||||
if (isUs) {
|
||||
@@ -1129,13 +1144,18 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
}
|
||||
}
|
||||
buf.append("</i><br />\n");
|
||||
buf.append("Stats: <br /><i><code>\n");
|
||||
for (Iterator iter = info.getOptions().keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = info.getOption(key);
|
||||
buf.append(DataHelper.stripHTML(key)).append(" = ").append(DataHelper.stripHTML(val)).append("<br />\n");
|
||||
if (full) {
|
||||
buf.append("Stats: <br /><i><code>\n");
|
||||
for (Iterator iter = info.getOptions().keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = info.getOption(key);
|
||||
buf.append(DataHelper.stripHTML(key)).append(" = ").append(DataHelper.stripHTML(val)).append("<br />\n");
|
||||
}
|
||||
buf.append("</code></i>\n");
|
||||
} else {
|
||||
buf.append("<a href=\"netdb.jsp?r=").append(hash.substring(0, 6)).append("\" >Full entry</a>\n");
|
||||
}
|
||||
buf.append("</code></i><hr />\n");
|
||||
buf.append("<hr />\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -65,10 +65,6 @@ class PersistentDataStore extends TransientDataStore {
|
||||
return super.remove(key);
|
||||
}
|
||||
|
||||
public DataStructure removeLease(Hash key) {
|
||||
return super.removeLease(key);
|
||||
}
|
||||
|
||||
public void put(Hash key, DataStructure data) {
|
||||
if ( (data == null) || (key == null) ) return;
|
||||
super.put(key, data);
|
||||
@@ -77,26 +73,6 @@ class PersistentDataStore extends TransientDataStore {
|
||||
_writer.queue(key, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't store leasesets here anymore, use the TransientDataStore count
|
||||
*
|
||||
public int countLeaseSets() {
|
||||
File dbDir = null;
|
||||
try {
|
||||
dbDir = getDbDir();
|
||||
} catch (IOException ioe) {
|
||||
return 0;
|
||||
}
|
||||
if (dbDir == null)
|
||||
return 0;
|
||||
File leaseSetFiles[] = dbDir.listFiles(LeaseSetFilter.getInstance());
|
||||
if (leaseSetFiles == null)
|
||||
return 0;
|
||||
else
|
||||
return leaseSetFiles.length;
|
||||
}
|
||||
*/
|
||||
|
||||
private void accept(LeaseSet ls) {
|
||||
super.put(ls.getDestination().calculateHash(), ls);
|
||||
}
|
||||
@@ -249,18 +225,6 @@ class PersistentDataStore extends TransientDataStore {
|
||||
int routerCount = 0;
|
||||
try {
|
||||
File dbDir = getDbDir();
|
||||
/****
|
||||
if (getContext().router().getUptime() < 10*60*1000) {
|
||||
File leaseSetFiles[] = dbDir.listFiles(LeaseSetFilter.getInstance());
|
||||
if (leaseSetFiles != null) {
|
||||
for (int i = 0; i < leaseSetFiles.length; i++) {
|
||||
Hash key = getLeaseSetHash(leaseSetFiles[i].getName());
|
||||
if ( (key != null) && (!isKnown(key)) )
|
||||
PersistentDataStore.this._context.jobQueue().addJob(new ReadLeaseJob(leaseSetFiles[i], key));
|
||||
}
|
||||
}
|
||||
}
|
||||
****/
|
||||
File routerInfoFiles[] = dbDir.listFiles(RouterInfoFilter.getInstance());
|
||||
if (routerInfoFiles != null) {
|
||||
routerCount += routerInfoFiles.length;
|
||||
@@ -283,63 +247,6 @@ class PersistentDataStore extends TransientDataStore {
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
private class ReadLeaseJob extends JobImpl {
|
||||
private File _leaseFile;
|
||||
private Hash _key;
|
||||
public ReadLeaseJob(File leaseFile, Hash key) {
|
||||
super(PersistentDataStore.this._context);
|
||||
_leaseFile = leaseFile;
|
||||
_key = key;
|
||||
}
|
||||
public String getName() { return "Read LeaseSet"; }
|
||||
private boolean shouldRead() {
|
||||
DataStructure data = get(_key);
|
||||
if (data == null) return true;
|
||||
if (data instanceof LeaseSet) {
|
||||
long knownDate = ((LeaseSet)data).getEarliestLeaseDate();
|
||||
long fileDate = _leaseFile.lastModified();
|
||||
if (fileDate > knownDate)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else {
|
||||
// wtf
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public void runJob() {
|
||||
if (!shouldRead()) return;
|
||||
try {
|
||||
FileInputStream fis = null;
|
||||
boolean corrupt = false;
|
||||
try {
|
||||
fis = new FileInputStream(_leaseFile);
|
||||
LeaseSet ls = new LeaseSet();
|
||||
ls.readBytes(fis);
|
||||
try {
|
||||
_facade.store(ls.getDestination().calculateHash(), ls);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
_log.info("Refused locally loaded leaseSet - deleting");
|
||||
corrupt = true;
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.warn("Error reading the leaseSet from " + _leaseFile.getAbsolutePath(), dfe);
|
||||
corrupt = true;
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.debug("Deleted prior to read.. a race during expiration / load");
|
||||
corrupt = false;
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
if (corrupt) _leaseFile.delete();
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("Error reading the leaseSet from " + _leaseFile.getAbsolutePath(), ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
****/
|
||||
|
||||
private class ReadRouterJob extends JobImpl {
|
||||
private File _routerFile;
|
||||
private Hash _key;
|
||||
@@ -464,31 +371,8 @@ class PersistentDataStore extends TransientDataStore {
|
||||
_log.info("Removed router info at " + f.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
/***
|
||||
String lsName = getLeaseSetName(key);
|
||||
File f = new File(dir, lsName);
|
||||
if (f.exists()) {
|
||||
boolean removed = f.delete();
|
||||
if (!removed)
|
||||
_log.warn("Unable to remove lease set at " + f.getAbsolutePath());
|
||||
else
|
||||
_log.info("Removed lease set at " + f.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
***/
|
||||
}
|
||||
|
||||
/***
|
||||
private final static class LeaseSetFilter implements FilenameFilter {
|
||||
private static final FilenameFilter _instance = new LeaseSetFilter();
|
||||
public static final FilenameFilter getInstance() { return _instance; }
|
||||
public boolean accept(File dir, String name) {
|
||||
if (name == null) return false;
|
||||
name = name.toUpperCase();
|
||||
return (name.startsWith(LEASESET_PREFIX.toUpperCase()) && name.endsWith(LEASESET_SUFFIX.toUpperCase()));
|
||||
}
|
||||
}
|
||||
***/
|
||||
private final static class RouterInfoFilter implements FilenameFilter {
|
||||
private static final FilenameFilter _instance = new RouterInfoFilter();
|
||||
public static final FilenameFilter getInstance() { return _instance; }
|
||||
|
@@ -28,6 +28,13 @@ import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* This used be called from StartAcceptingClientsJob but is now disabled.
|
||||
* It is still called once from LoadRouterInfoJob (but not run as a Job).
|
||||
*
|
||||
* The following comments appear to be incorrect...
|
||||
* it rebuilds if the router.info file does not exist.
|
||||
* There is no check for a router.info.rebuild file.
|
||||
*
|
||||
* If the file router.info.rebuild exists, rebuild the router info and republish.
|
||||
* This is useful for dhcp or other situations where the router addresses change -
|
||||
* simply create the router.info.rebuild file after modifying router.config and within
|
||||
|
@@ -28,7 +28,8 @@ public class StartAcceptingClientsJob extends JobImpl {
|
||||
getContext().clientManager().startup();
|
||||
|
||||
getContext().jobQueue().addJob(new ReadConfigJob(getContext()));
|
||||
getContext().jobQueue().addJob(new RebuildRouterInfoJob(getContext()));
|
||||
// pointless
|
||||
//getContext().jobQueue().addJob(new RebuildRouterInfoJob(getContext()));
|
||||
getContext().jobQueue().allowParallelOperation();
|
||||
}
|
||||
}
|
||||
|
@@ -507,7 +507,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
||||
}
|
||||
out.write("</table>\n");
|
||||
out.write("Inactive participating tunnels: " + inactive + "<br />\n");
|
||||
out.write("Lifetime bandwidth usage: " + processed + "KB<br />\n");
|
||||
out.write("Lifetime bandwidth usage: " + DataHelper.formatSize(processed*1024) + "B<br />\n");
|
||||
}
|
||||
|
||||
class TunnelComparator implements Comparator {
|
||||
@@ -577,7 +577,8 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
||||
}
|
||||
if (live <= 0)
|
||||
out.write("<b>No tunnels, waiting for the grace period to end</b><br />\n");
|
||||
out.write("Lifetime bandwidth usage: " + processedIn + "KB in, " + processedOut + "KB out<br />");
|
||||
out.write("Lifetime bandwidth usage: " + DataHelper.formatSize(processedIn*1024) + "B in, " +
|
||||
DataHelper.formatSize(processedOut*1024) + "B out<br />");
|
||||
}
|
||||
|
||||
private String getCapacity(Hash peer) {
|
||||
|
Reference in New Issue
Block a user