use of net.i2p.router.TunnelPoolSettings in project i2p.i2p by i2p.
the class NetDbRenderer method renderLeaseSetHTML.
/**
* @param debug @since 0.7.14 sort by distance from us, display
* median distance, and other stuff, useful when floodfill
*/
public void renderLeaseSetHTML(Writer out, boolean debug) throws IOException {
StringBuilder buf = new StringBuilder(4 * 1024);
if (debug)
buf.append("<p id=\"debugmode\">Debug mode - Sorted by hash distance, closest first</p>\n");
Hash ourRKey;
Set<LeaseSet> leases;
DecimalFormat fmt;
if (debug) {
ourRKey = _context.routerHash();
leases = new TreeSet<LeaseSet>(new LeaseSetRoutingKeyComparator(ourRKey));
fmt = new DecimalFormat("#0.00");
} else {
ourRKey = null;
leases = new TreeSet<LeaseSet>(new LeaseSetComparator());
fmt = null;
}
leases.addAll(_context.netDb().getLeases());
int medianCount = 0;
int rapCount = 0;
BigInteger median = null;
int c = 0;
// Summary
FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade) _context.netDb();
if (debug) {
buf.append("<table id=\"leasesetdebug\">\n");
} else {
buf.append("<table id=\"leasesetsummary\">\n");
}
buf.append("<tr><th colspan=\"3\">Leaseset Summary</th>").append("<th><a href=\"/configadvanced\" title=\"").append(_t("Manually Configure Floodfill Participation")).append("\">[").append(_t("Configure Floodfill Participation")).append("]</a></th></tr>\n").append("<tr><td><b>Total Leasesets:</b></td><td colspan=\"3\">").append(leases.size()).append("</td></tr>\n");
if (debug) {
buf.append("<tr><td><b>Published (RAP) Leasesets:</b></td><td colspan=\"3\">").append(netdb.getKnownLeaseSets()).append("</td></tr>\n").append("<tr><td><b>Mod Data:</b></td><td>").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData())).append("</td>").append("<td><b>Last Changed:</b></td><td>").append(new Date(_context.routerKeyGenerator().getLastChanged())).append("</td></tr>\n").append("<tr><td><b>Next Mod Data:</b></td><td>").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData())).append("</td>").append("<td><b>Change in:</b></td><td>").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight())).append("</td></tr>\n");
}
int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size();
buf.append("<tr><td><b>Known Floodfills:</b></td><td colspan=\"3\">").append(ff).append("</td></tr>\n").append("<tr><td><b>Currently Floodfill?</b></td><td colspan=\"3\">").append(netdb.floodfillEnabled() ? "yes" : "no").append("</td></tr>\n");
buf.append("</table>\n");
if (leases.isEmpty()) {
if (!debug)
buf.append("<div id=\"noleasesets\"><i>").append(_t("No Leasesets currently active.")).append("</i></div>");
} else {
if (debug) {
// Find the center of the RAP leasesets
for (LeaseSet ls : leases) {
if (ls.getReceivedAsPublished())
rapCount++;
}
medianCount = rapCount / 2;
}
boolean linkSusi = WebAppStarter.isWebAppRunning("susidns");
long now = _context.clock().now();
buf.append("<div class=\"leasesets_container\">");
for (LeaseSet ls : leases) {
Destination dest = ls.getDestination();
Hash key = dest.calculateHash();
buf.append("<table class=\"leaseset\">\n").append("<tr><th><b>").append(_t("LeaseSet")).append(":</b> <code>").append(key.toBase64()).append("</code>");
if (_context.keyRing().get(key) != null)
buf.append(" (").append(_t("Encrypted")).append(')');
buf.append("</th>");
if (_context.clientManager().isLocal(dest)) {
buf.append("<th><a href=\"tunnels#" + key.toBase64().substring(0, 4) + "\">" + _t("Local") + "</a> ");
boolean unpublished = !_context.clientManager().shouldPublishLeaseSet(key);
if (unpublished)
buf.append("<b>").append(_t("Unpublished")).append("</b> ");
buf.append("<b>").append(_t("Destination")).append(":</b> ");
TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(key);
if (in != null && in.getDestinationNickname() != null)
buf.append(in.getDestinationNickname());
else
buf.append(dest.toBase64().substring(0, 6));
buf.append("</th></tr>\n<tr><td");
// If the dest is published but not in the addressbook, an extra
// <td> is appended with an "Add to addressbook" link, so this
// <td> should not span 2 columns.
String host = null;
if (!unpublished) {
host = _context.namingService().reverseLookup(dest);
}
if (unpublished || host != null || !linkSusi) {
buf.append(" colspan=\"2\"");
}
buf.append(">");
String b32 = dest.toBase32();
buf.append("<a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>");
if (linkSusi && !unpublished) {
if (host == null) {
buf.append("<td class=\"addtobook\" colspan=\"2\">").append("<a title=\"").append(_t("Add to addressbook")).append("\" href=\"/susidns/addressbook.jsp?book=private&destination=").append(dest.toBase64()).append("#add\">").append(_t("Add to local addressbook")).append("</a></td>");
}
}
// else probably a client
} else {
buf.append("<th><b>").append(_t("Destination")).append(":</b> ");
String host = _context.namingService().reverseLookup(dest);
if (host != null) {
buf.append("<a href=\"http://").append(host).append("/\">").append(host).append("</a></th>");
} else {
String b32 = dest.toBase32();
buf.append("<code>").append(dest.toBase64().substring(0, 6)).append("</code></th>").append("</tr>\n<tr><td");
if (!linkSusi)
buf.append(" colspan=\"2\"");
buf.append("><a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>\n");
if (linkSusi) {
buf.append("<td class=\"addtobook\"><a title=\"").append(_t("Add to addressbook")).append("\" href=\"/susidns/addressbook.jsp?book=private&destination=").append(dest.toBase64()).append("#add\">").append(_t("Add to local addressbook")).append("</a></td>");
}
}
}
buf.append("</tr>\n<tr><td colspan=\"2\">\n");
long exp = ls.getLatestLeaseDate() - now;
if (exp > 0)
buf.append("<b>").append(_t("Expires in {0}", DataHelper.formatDuration2(exp))).append("</b>");
else
buf.append("<b>").append(_t("Expired {0} ago", DataHelper.formatDuration2(0 - exp))).append("</b>");
buf.append("</td></tr>\n");
if (debug) {
buf.append("<tr><td colspan=\"2\">");
buf.append("<b>RAP?</b> ").append(ls.getReceivedAsPublished());
buf.append(" <b>RAR?</b> ").append(ls.getReceivedAsReply());
BigInteger dist = HashDistance.getDistance(ourRKey, ls.getRoutingKey());
if (ls.getReceivedAsPublished()) {
if (c++ == medianCount)
median = dist;
}
buf.append(" <b>Distance: </b>").append(fmt.format(biLog2(dist)));
buf.append("</td></tr>\n<tr><td colspan=\"2\">");
// buf.append(dest.toBase32()).append("<br>");
buf.append("<b>Signature type:</b> ").append(dest.getSigningPublicKey().getType());
buf.append(" <b>Encryption Key:</b> ").append(ls.getEncryptionKey().toBase64().substring(0, 20)).append("…");
buf.append("</td></tr>\n<tr><td colspan=\"2\">");
buf.append("<b>Routing Key:</b> ").append(ls.getRoutingKey().toBase64());
buf.append("</td></tr>");
}
buf.append("<tr><td colspan=\"2\"><ul class=\"netdb_leases\">");
for (int i = 0; i < ls.getLeaseCount(); i++) {
Lease lease = ls.getLease(i);
buf.append("<li><b>").append(_t("Lease")).append(' ').append(i + 1).append(":</b> <span class=\"netdb_gateway\" title=\"").append(_t("Gateway")).append("\"><img src=\"themes/console/images/info/gateway.png\" alt=\"").append(_t("Gateway")).append("\"></span> <span class=\"tunnel_peer\">");
buf.append(_context.commSystem().renderPeerHTML(lease.getGateway()));
buf.append("</span> <span class=\"netdb_tunnel\">").append(_t("Tunnel")).append(" <span class=\"tunnel_id\">").append(lease.getTunnelId().getTunnelId()).append("</span></span> ");
if (debug) {
long exl = lease.getEndDate().getTime() - now;
if (exl > 0)
buf.append("<b class=\"netdb_expiry\">").append(_t("Expires in {0}", DataHelper.formatDuration2(exl))).append("</b>");
else
buf.append("<b class=\"netdb_expiry\">").append(_t("Expired {0} ago", DataHelper.formatDuration2(0 - exl))).append("</b>");
}
buf.append("</li>");
}
buf.append("</ul></td></tr>\n");
buf.append("</table>\n");
out.write(buf.toString());
buf.setLength(0);
}
// for each
if (debug) {
buf.append("<table id=\"leasesetdebug\"><tr><td><b>Network data (only valid if floodfill):</b></td><td colspan=\"3\">");
// buf.append("</b></p><p><b>Center of Key Space (router hash): " + ourRKey.toBase64());
if (median != null) {
double log2 = biLog2(median);
buf.append("</td></tr>").append("<tr><td><b>Median distance (bits):</b></td><td colspan=\"3\">").append(fmt.format(log2)).append("</td></tr>\n");
// 2 for 4 floodfills... -1 for median
// this can be way off for unknown reasons
int total = (int) Math.round(Math.pow(2, 2 + 256 - 1 - log2));
buf.append("<tr><td><b>Estimated total floodfills:</b></td><td colspan=\"3\">").append(total).append("</td></tr>\n");
buf.append("<tr><td><b>Estimated total leasesets:</b></td><td colspan=\"3\">").append(total * rapCount / 4);
} else {
buf.append("<i>Not floodfill or no data.</i>");
}
buf.append("</td></tr></table>\n");
}
// median table
buf.append("</div>");
}
// !empty
out.write(buf.toString());
out.flush();
}
use of net.i2p.router.TunnelPoolSettings in project i2p.i2p by i2p.
the class SummaryHelper method getName.
/**
* translate here so collation works above
*/
private String getName(Destination d) {
TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(d.calculateHash());
String name = (in != null ? in.getDestinationNickname() : null);
if (name == null) {
TunnelPoolSettings out = _context.tunnelManager().getOutboundSettings(d.calculateHash());
name = (out != null ? out.getDestinationNickname() : null);
if (name == null)
name = d.calculateHash().toBase64().substring(0, 6);
else
name = _t(name);
} else {
name = _t(name);
}
return name;
}
use of net.i2p.router.TunnelPoolSettings in project i2p.i2p by i2p.
the class ExploratoryPeerSelector method selectPeers.
/**
* Returns ENDPOINT FIRST, GATEWAY LAST!!!!
* In: us .. closest .. middle .. IBGW
* Out: OBGW .. middle .. closest .. us
*
* @return ordered list of Hash objects (one per peer) specifying what order
* they should appear in a tunnel (ENDPOINT FIRST). This includes
* the local router in the list. If there are no tunnels or peers
* to build through, and the settings reject 0 hop tunnels, this will
* return null.
*/
public List<Hash> selectPeers(TunnelPoolSettings settings) {
int length = getLength(settings);
if (length < 0) {
if (log.shouldLog(Log.DEBUG))
log.debug("Length requested is zero: " + settings);
return null;
}
// if (false && shouldSelectExplicit(settings)) {
// List<Hash> rv = selectExplicit(settings, length);
// if (l.shouldLog(Log.DEBUG))
// l.debug("Explicit peers selected: " + rv);
// return rv;
// }
boolean isInbound = settings.isInbound();
Set<Hash> exclude = getExclude(isInbound, true);
exclude.add(ctx.routerHash());
// special cases
boolean nonzero = length > 0;
boolean exploreHighCap = nonzero && shouldPickHighCap();
boolean v6Only = nonzero && isIPv6Only();
boolean ntcpDisabled = nonzero && isNTCPDisabled();
boolean ssuDisabled = nonzero && isSSUDisabled();
boolean checkClosestHop = v6Only || ntcpDisabled || ssuDisabled;
boolean hidden = nonzero && (ctx.router().isHidden() || ctx.router().getRouterInfo().getAddressCount() <= 0);
boolean hiddenInbound = hidden && isInbound;
boolean hiddenOutbound = hidden && !isInbound;
boolean lowOutbound = nonzero && !isInbound && !ctx.commSystem().haveHighOutboundCapacity();
// closest-hop restrictions
// Since we're applying orderPeers() later, we don't know
// which will be the closest hop, so select the closest one here if necessary.
Hash closestHop = null;
if (v6Only || hiddenInbound || lowOutbound) {
Set<Hash> closestExclude;
if (checkClosestHop) {
closestExclude = getClosestHopExclude(isInbound);
if (closestExclude != null)
closestExclude.addAll(exclude);
else
closestExclude = exclude;
} else {
closestExclude = exclude;
}
Set<Hash> closest = new HashSet<Hash>(1);
if (hiddenInbound || lowOutbound) {
// use only connected peers so we don't make more connections
if (log.shouldLog(Log.INFO))
log.info("EPS SANFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
// SANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(closestExclude);
ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest);
if (closest.isEmpty()) {
// ANFP does not fall back to non-connected
if (log.shouldLog(Log.INFO))
log.info("EPS SFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
ctx.profileOrganizer().selectFastPeers(1, closestExclude, closest);
}
} else if (exploreHighCap) {
if (log.shouldLog(Log.INFO))
log.info("EPS SHCP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
ctx.profileOrganizer().selectHighCapacityPeers(1, closestExclude, closest);
} else {
if (log.shouldLog(Log.INFO))
log.info("EPS SNFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
ctx.profileOrganizer().selectNotFailingPeers(1, closestExclude, closest, false);
}
if (!closest.isEmpty()) {
closestHop = closest.iterator().next();
exclude.add(closestHop);
length--;
}
}
// furthest-hop restrictions
// Since we're applying orderPeers() later, we don't know
// which will be the furthest hop, so select the furthest one here if necessary.
Hash furthestHop = null;
if (hiddenOutbound && length > 0) {
// OBEP
// check for hidden and outbound, and the paired (inbound) tunnel is zero-hop
// if so, we need the OBEP to be connected to us, so we get the build reply back
// This should be rare except at startup
TunnelManagerFacade tmf = ctx.tunnelManager();
TunnelPool tp = tmf.getInboundExploratoryPool();
TunnelPoolSettings tps = tp.getSettings();
int len = tps.getLength();
boolean pickFurthest = true;
if (len <= 0 || tps.getLengthOverride() == 0 || len + tps.getLengthVariance() <= 0) {
// leave it true
} else {
for (TunnelInfo ti : tp.listTunnels()) {
if (ti.getLength() > 1) {
pickFurthest = false;
break;
}
}
}
if (pickFurthest) {
Set<Hash> furthest = new HashSet<Hash>(1);
if (log.shouldLog(Log.INFO))
log.info("EPS SANFP furthest OB exclude " + exclude.size());
// ANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(exclude);
ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest);
if (furthest.isEmpty()) {
// ANFP does not fall back to non-connected
if (log.shouldLog(Log.INFO))
log.info("EPS SFP furthest OB exclude " + exclude.size());
ctx.profileOrganizer().selectFastPeers(1, exclude, furthest);
}
if (!furthest.isEmpty()) {
furthestHop = furthest.iterator().next();
exclude.add(furthestHop);
length--;
}
}
}
// Don't use ff peers for exploratory tunnels to lessen exposure to netDb searches and stores
// Hmm if they don't get explored they don't get a speed/capacity rating
// so they don't get used for client tunnels either.
// FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb();
// exclude.addAll(fac.getFloodfillPeers());
HashSet<Hash> matches = new HashSet<Hash>(length);
if (length > 0) {
//
if (exploreHighCap) {
if (log.shouldLog(Log.INFO))
log.info("EPS SHCP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size());
ctx.profileOrganizer().selectHighCapacityPeers(length, exclude, matches);
} else {
// Peer org credits existing items in matches
if (length > 2)
ctx.profileOrganizer().selectHighCapacityPeers(length - 2, exclude, matches);
if (log.shouldLog(Log.INFO))
log.info("EPS SNFP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size());
ctx.profileOrganizer().selectNotFailingPeers(length, exclude, matches, false);
}
matches.remove(ctx.routerHash());
}
ArrayList<Hash> rv = new ArrayList<Hash>(matches);
if (rv.size() > 1)
orderPeers(rv, settings.getRandomKey());
if (closestHop != null) {
if (isInbound)
rv.add(0, closestHop);
else
rv.add(closestHop);
length++;
}
if (furthestHop != null) {
// always OBEP for now, nothing special for IBGW
if (isInbound)
rv.add(furthestHop);
else
rv.add(0, furthestHop);
length++;
}
// log.debug("EPS result: " + DataHelper.toString(rv));
if (isInbound)
rv.add(0, ctx.routerHash());
else
rv.add(ctx.routerHash());
if (rv.size() > 1) {
if (!checkTunnel(isInbound, rv))
rv = null;
}
return rv;
}
use of net.i2p.router.TunnelPoolSettings in project i2p.i2p by i2p.
the class TunnelPool method configureNewTunnel.
/**
* @return null on failure
*/
private PooledTunnelCreatorConfig configureNewTunnel(boolean forceZeroHop) {
TunnelPoolSettings settings = getSettings();
// peers for new tunnel, including us, ENDPOINT FIRST
List<Hash> peers = null;
long now = _context.clock().now();
long expiration = now + TunnelPoolSettings.DEFAULT_DURATION;
if (!forceZeroHop) {
int len = settings.getLengthOverride();
if (len < 0)
len = settings.getLength();
if (len > 0 && (!settings.isExploratory()) && _context.random().nextBoolean()) {
// look for a tunnel to reuse, if the right length and expiring soon
// ignore variance for now.
// us
len++;
synchronized (_tunnels) {
for (TunnelInfo ti : _tunnels) {
if (ti.getLength() >= len && ti.getExpiration() < now + 3 * 60 * 1000 && !ti.wasReused()) {
ti.setReused();
len = ti.getLength();
peers = new ArrayList<Hash>(len);
// peers list is ordered endpoint first, but cfg.getPeer() is ordered gateway first
for (int i = len - 1; i >= 0; i--) {
peers.add(ti.getPeer(i));
}
break;
}
}
}
}
if (peers == null) {
setLengthOverride();
peers = _peerSelector.selectPeers(settings);
}
if ((peers == null) || (peers.isEmpty())) {
// the pool is refusing 0 hop tunnels
if (peers == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No peers to put in the new tunnel! selectPeers returned null! boo, hiss!");
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("No peers to put in the new tunnel! selectPeers returned an empty list?!");
}
return null;
}
} else {
peers = Collections.singletonList(_context.routerHash());
}
PooledTunnelCreatorConfig cfg = new PooledTunnelCreatorConfig(_context, peers.size(), settings.isInbound(), settings.getDestination());
cfg.setTunnelPool(this);
// peers list is ordered endpoint first, but cfg.getPeer() is ordered gateway first
for (int i = 0; i < peers.size(); i++) {
int j = peers.size() - 1 - i;
cfg.setPeer(j, peers.get(i));
HopConfig hop = cfg.getConfig(j);
hop.setCreation(now);
hop.setExpiration(expiration);
hop.setIVKey(_context.keyGenerator().generateSessionKey());
hop.setLayerKey(_context.keyGenerator().generateSessionKey());
// tunnelIds will be updated during building, and as the creator, we
// don't need to worry about prev/next hop
}
// note that this will be adjusted by expire job
cfg.setExpiration(expiration);
if (!settings.isInbound())
cfg.setPriority(settings.getPriority());
if (_log.shouldLog(Log.DEBUG))
_log.debug("Config contains " + peers + ": " + cfg);
synchronized (_inProgress) {
_inProgress.add(cfg);
}
return cfg;
}
use of net.i2p.router.TunnelPoolSettings in project i2p.i2p by i2p.
the class TunnelPoolManager method addAlias.
/**
* Add another destination to the same tunnels.
* Must have same encryption key and a different signing key.
* @throws IllegalArgumentException if not
* @return success
* @since 0.9.21
*/
public boolean addAlias(Destination dest, ClientTunnelSettings settings, Destination existingClient) {
if (dest.getSigningPublicKey().equals(existingClient.getSigningPublicKey()))
throw new IllegalArgumentException("signing key must differ");
if (!dest.getPublicKey().equals(existingClient.getPublicKey()))
throw new IllegalArgumentException("encryption key mismatch");
Hash h = dest.calculateHash();
Hash e = existingClient.calculateHash();
synchronized (this) {
TunnelPool inbound = _clientInboundPools.get(h);
TunnelPool outbound = _clientOutboundPools.get(h);
if (inbound != null || outbound != null) {
if (_log.shouldLog(Log.WARN))
_log.warn("already have alias " + dest.toBase32());
return false;
}
TunnelPool eInbound = _clientInboundPools.get(e);
TunnelPool eOutbound = _clientOutboundPools.get(e);
if (eInbound == null || eOutbound == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("primary not found " + existingClient);
return false;
}
eInbound.getSettings().getAliases().add(h);
eOutbound.getSettings().getAliases().add(h);
TunnelPoolSettings newIn = settings.getInboundSettings();
TunnelPoolSettings newOut = settings.getOutboundSettings();
newIn.setAliasOf(e);
newOut.setAliasOf(e);
inbound = new AliasedTunnelPool(_context, this, newIn, eInbound);
outbound = new AliasedTunnelPool(_context, this, newOut, eOutbound);
_clientInboundPools.put(h, inbound);
_clientOutboundPools.put(h, outbound);
inbound.startup();
outbound.startup();
}
if (_log.shouldLog(Log.WARN))
_log.warn("Added " + dest.toBase32() + " as alias for " + existingClient.toBase32() + " with settings " + settings);
return true;
}
Aggregations