2005-09-07 BarkerJr

* HTML cleanup for the router console (thanks!)
2005-09-07  jrandom
    * Lay the foundation for 'client routers' - the ability for peers to opt
      out of participating in tunnels entirely due to firewall/NAT issues.
      Individual routers have control over where those peers are used in
      tunnels - in outbound or inbound, exploratory or client tunnels, or
      none at all.  The defaults with this build are to simply act as before -
      placing everyone as potential participants in any tunnel.
    * Another part of the foundation includes the option for netDb
      participants to refuse to answer queries regarding peers who are marked
      as unreachable, though this too is disabled by default (meaning the
      routerInfo is retrievable from the netDb).
This commit is contained in:
jrandom
2005-09-07 22:31:11 +00:00
committed by zzz
parent c2ea8db683
commit 54074e76b5
24 changed files with 347 additions and 93 deletions

View File

@ -2,7 +2,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head> <html><head>
<title>I2P Router Console - logs</title> <title>I2P Router Console - config networking</title>
<link rel="stylesheet" href="default.css" type="text/css" /> <link rel="stylesheet" href="default.css" type="text/css" />
</head><body> </head><body>

View File

@ -3,7 +3,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head> <html><head>
<title>I2P Router Console - config clients</title> <title>I2P Router Console - config logging</title>
<link rel="stylesheet" href="default.css" type="text/css" /> <link rel="stylesheet" href="default.css" type="text/css" />
</head><body> </head><body>
<jsp:useBean class="net.i2p.router.web.ConfigLoggingHelper" id="logginghelper" scope="request" /> <jsp:useBean class="net.i2p.router.web.ConfigLoggingHelper" id="logginghelper" scope="request" />

View File

@ -3,7 +3,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head> <html><head>
<title>I2P Router Console - config clients</title> <title>I2P Router Console - config service</title>
<link rel="stylesheet" href="default.css" type="text/css" /> <link rel="stylesheet" href="default.css" type="text/css" />
</head><body> </head><body>

View File

@ -3,7 +3,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head> <html><head>
<title>I2P Router Console - home</title> <title>I2P Router Console - internals</title>
<link rel="stylesheet" href="default.css" type="text/css" /> <link rel="stylesheet" href="default.css" type="text/css" />
</head><body> </head><body>

View File

@ -3,7 +3,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head> <html><head>
<title>I2P Router Console - home</title> <title>I2P Router Console - statistics</title>
<link rel="stylesheet" href="default.css" type="text/css" /> <link rel="stylesheet" href="default.css" type="text/css" />
</head><body> </head><body>

View File

@ -1,4 +1,19 @@
$Id: history.txt,v 1.239 2005/09/04 15:26:42 jrandom Exp $ $Id: history.txt,v 1.240 2005/09/05 14:30:09 jrandom Exp $
2005-09-07 BarkerJr
* HTML cleanup for the router console (thanks!)
2005-09-07 jrandom
* Lay the foundation for 'client routers' - the ability for peers to opt
out of participating in tunnels entirely due to firewall/NAT issues.
Individual routers have control over where those peers are used in
tunnels - in outbound or inbound, exploratory or client tunnels, or
none at all. The defaults with this build are to simply act as before -
placing everyone as potential participants in any tunnel.
* Another part of the foundation includes the option for netDb
participants to refuse to answer queries regarding peers who are marked
as unreachable, though this too is disabled by default (meaning the
routerInfo is retrievable from the netDb).
2005-09-05 jrandom 2005-09-05 jrandom
* Expose the HTTP headers to EepGet status listeners * Expose the HTTP headers to EepGet status listeners

View File

@ -5,13 +5,12 @@ the number of "Active: " peers rise, and you should see some local "destinations
listed (if not, <a href="#trouble">see below</a>). Once those are up, you can:</p> listed (if not, <a href="#trouble">see below</a>). Once those are up, you can:</p>
<ul> <ul>
<li><b>chat anonymously</b> - fire up your own IRC client and connect to the <li><b>chat anonymously</b> - fire up your own IRC client and connect to the
server at <b>localhost port 6668</b>. This points at one of three anonymously hosted server at <b>localhost port 6668</b>. This points at one of two anonymously hosted
IRC servers, but neither you nor they know where the other is.</li> IRC servers, but neither you nor they know where the other is.</li>
<li><b>browse "eepsites"</b> - on I2P there are anonymously hosted websites - <li><b>browse "eepsites"</b> - on I2P there are anonymously hosted websites -
tell your browser to use the <b>HTTP proxy at localhost port 4444</b>, then tell your browser to use the <b>HTTP proxy at localhost port 4444</b>, then
browse to an eepsite - browse to an eepsite -
<ul> <ul>
<li><a href="http://duck.i2p/">duck.i2p</a>: duck's eepsite, with links to other active sites</li>
<li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li> <li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li>
<li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li> <li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li>
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li> <li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
@ -21,7 +20,7 @@ listed (if not, <a href="#trouble">see below</a>). Once those are up, you can:<
</ul> </ul>
There are many more eepsites - just follow the links from the ones you see, There are many more eepsites - just follow the links from the ones you see,
bookmark your favorites, and visit them often!</li> bookmark your favorites, and visit them often!</li>
<li><b>browse the web</b> - there are a pair of HTTP "outproxies" in I2P hooked <li><b>browse the web</b> - there is currently an HTTP "outproxy" in I2P hooked
up to your own HTTP proxy on port 4444 - simply set your browser's proxy to up to your own HTTP proxy on port 4444 - simply set your browser's proxy to
use it (as above) and go to any normal URL - your requests will be bounced use it (as above) and go to any normal URL - your requests will be bounced
through the I2P network.</li> through the I2P network.</li>
@ -64,7 +63,6 @@ hand side of the page will show up to help you when necessary).</p>
<p>If you are still having problems, you may want to review the information on the <p>If you are still having problems, you may want to review the information on the
<a href="http://www.i2p.net/">I2P website</a>, post up messages to the <a href="http://www.i2p.net/">I2P website</a>, post up messages to the
<a href="http://forum.i2p.net/">I2P discussion forum</a>, or swing by #i2p or <a href="http://forum.i2p.net/">I2P discussion forum</a>, or swing by #i2p or
#i2p-chat on IRC at <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p, irc.freshcoffee.i2p or #i2p-chat on IRC at <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p or irc.freshcoffee.i2p (they're linked together).</p>
irc.arcturus.i2p (they're all linked together).</p>
<p><b>As a note, you can change this page by editing the file "docs/readme.html"</b></p> <p><b>As a note, you can change this page by editing the file "docs/readme.html"</b></p>

View File

@ -10,6 +10,7 @@ package net.i2p.router;
import java.io.Writer; import java.io.Writer;
import java.util.List; import java.util.List;
import net.i2p.data.Hash;
/** /**
* Manage peer references and keep them up to date so that when asked for peers, * Manage peer references and keep them up to date so that when asked for peers,
@ -25,6 +26,10 @@ public interface PeerManagerFacade extends Service {
* @return List of Hash objects of the RouterIdentity for matching peers * @return List of Hash objects of the RouterIdentity for matching peers
*/ */
public List selectPeers(PeerSelectionCriteria criteria); public List selectPeers(PeerSelectionCriteria criteria);
public List getPeersByCapability(char capability);
public void setCapabilities(Hash peer, String caps);
public void removeCapabilities(Hash peer);
public Hash selectRandomByCapability(char capability);
} }
class DummyPeerManagerFacade implements PeerManagerFacade { class DummyPeerManagerFacade implements PeerManagerFacade {
@ -33,4 +38,8 @@ class DummyPeerManagerFacade implements PeerManagerFacade {
public void restart() {} public void restart() {}
public void renderStatusHTML(Writer out) { } public void renderStatusHTML(Writer out) { }
public List selectPeers(PeerSelectionCriteria criteria) { return null; } public List selectPeers(PeerSelectionCriteria criteria) { return null; }
public List getPeersByCapability(char capability) { return null; }
public void setCapabilities(Hash peer, String caps) {}
public void removeCapabilities(Hash peer) {}
public Hash selectRandomByCapability(char capability) { return null; }
} }

View File

@ -294,6 +294,7 @@ public class Router {
ri.setAddresses(_context.commSystem().createAddresses()); ri.setAddresses(_context.commSystem().createAddresses());
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context)) if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context))
ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
addReachabilityCapability(ri);
SigningPrivateKey key = _context.keyManager().getSigningPrivateKey(); SigningPrivateKey key = _context.keyManager().getSigningPrivateKey();
if (key == null) { if (key == null) {
_log.log(Log.CRIT, "Internal error - signing private key not known? wtf"); _log.log(Log.CRIT, "Internal error - signing private key not known? wtf");
@ -312,6 +313,30 @@ public class Router {
} }
} }
public static final char CAPABILITY_REACHABLE = 'R';
public static final char CAPABILITY_UNREACHABLE = 'U';
public static final String PROP_FORCE_UNREACHABLE = "router.forceUnreachable";
public void addReachabilityCapability(RouterInfo ri) {
String forceUnreachable = _context.getProperty(PROP_FORCE_UNREACHABLE);
if ( (forceUnreachable != null) && ("true".equalsIgnoreCase(forceUnreachable)) ) {
ri.addCapability(CAPABILITY_UNREACHABLE);
return;
}
switch (_context.commSystem().getReachabilityStatus()) {
case CommSystemFacade.STATUS_OK:
ri.addCapability(CAPABILITY_REACHABLE);
break;
case CommSystemFacade.STATUS_DIFFERENT:
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
ri.addCapability(CAPABILITY_UNREACHABLE);
break;
case CommSystemFacade.STATUS_UNKNOWN:
// no explicit capability
break;
}
}
/** /**
* Ugly list of files that we need to kill if we are building a new identity * Ugly list of files that we need to kill if we are building a new identity
* *

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
* *
*/ */
public class RouterVersion { public class RouterVersion {
public final static String ID = "$Revision: 1.226 $ $Date: 2005/09/02 14:10:06 $"; public final static String ID = "$Revision: 1.227 $ $Date: 2005/09/04 14:15:49 $";
public final static String VERSION = "0.6.0.5"; public final static String VERSION = "0.6.0.5";
public final static long BUILD = 1; public final static long BUILD = 2;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION); System.out.println("I2P Router version: " + VERSION);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -9,6 +9,7 @@ package net.i2p.router.networkdb;
*/ */
import java.util.Iterator; import java.util.Iterator;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import net.i2p.data.DataStructure; import net.i2p.data.DataStructure;
@ -25,6 +26,7 @@ import net.i2p.data.i2np.TunnelGatewayMessage;
import net.i2p.router.Job; import net.i2p.router.Job;
import net.i2p.router.JobImpl; import net.i2p.router.JobImpl;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.Router;
import net.i2p.router.TunnelInfo; import net.i2p.router.TunnelInfo;
import net.i2p.router.message.SendMessageDirectJob; import net.i2p.router.message.SendMessageDirectJob;
import net.i2p.util.Log; import net.i2p.util.Log;
@ -109,11 +111,19 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
} else { } else {
RouterInfo info = getContext().netDb().lookupRouterInfoLocally(_message.getSearchKey()); RouterInfo info = getContext().netDb().lookupRouterInfoLocally(_message.getSearchKey());
if ( (info != null) && (info.isCurrent(EXPIRE_DELAY)) ) { if ( (info != null) && (info.isCurrent(EXPIRE_DELAY)) ) {
// send that routerInfo to the _message.getFromHash peer if (isUnreachable(info) && !publishUnreachable()) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("We do have key " + _message.getSearchKey().toBase64() _log.debug("Not answering a query for a netDb peer who isn't reachable");
+ " locally as a router info. sending to " + fromKey.toBase64()); Set us = new HashSet(1);
sendData(_message.getSearchKey(), info, fromKey, _message.getReplyTunnel()); us.add(getContext().router().getRouterInfo());
sendClosest(_message.getSearchKey(), us, fromKey, _message.getReplyTunnel());
} else {
// send that routerInfo to the _message.getFromHash peer
if (_log.shouldLog(Log.DEBUG))
_log.debug("We do have key " + _message.getSearchKey().toBase64()
+ " locally as a router info. sending to " + fromKey.toBase64());
sendData(_message.getSearchKey(), info, fromKey, _message.getReplyTunnel());
}
} else { } else {
// not found locally - return closest peer routerInfo structs // not found locally - return closest peer routerInfo structs
Set routerInfoSet = getContext().netDb().findNearestRouters(_message.getSearchKey(), Set routerInfoSet = getContext().netDb().findNearestRouters(_message.getSearchKey(),
@ -127,6 +137,24 @@ public class HandleDatabaseLookupMessageJob extends JobImpl {
} }
} }
private boolean isUnreachable(RouterInfo info) {
if (info == null) return true;
String cap = info.getCapabilities();
if (cap == null) return false;
return cap.indexOf(Router.CAPABILITY_REACHABLE) >= 0;
}
public static final String PROP_PUBLISH_UNREACHABLE = "router.publishUnreachableRouters";
public static final boolean DEFAULT_PUBLISH_UNREACHABLE = true;
private boolean publishUnreachable() {
String publish = getContext().getProperty(PROP_PUBLISH_UNREACHABLE);
if (publish != null)
return Boolean.valueOf(publish).booleanValue();
else
return DEFAULT_PUBLISH_UNREACHABLE;
}
private boolean weAreClosest(Set routerInfoSet) { private boolean weAreClosest(Set routerInfoSet) {
boolean weAreClosest = false; boolean weAreClosest = false;
for (Iterator iter = routerInfoSet.iterator(); iter.hasNext(); ) { for (Iterator iter = routerInfoSet.iterator(); iter.hasNext(); ) {

View File

@ -47,6 +47,7 @@ public class PublishLocalRouterInfoJob extends JobImpl {
ri.setAddresses(getContext().commSystem().createAddresses()); ri.setAddresses(getContext().commSystem().createAddresses());
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext()))
ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
getContext().router().addReachabilityCapability(ri);
SigningPrivateKey key = getContext().keyManager().getSigningPrivateKey(); SigningPrivateKey key = getContext().keyManager().getSigningPrivateKey();
if (key == null) { if (key == null) {
_log.log(Log.CRIT, "Internal error - signing private key not known? rescheduling publish for 30s"); _log.log(Log.CRIT, "Internal error - signing private key not known? rescheduling publish for 30s");

View File

@ -48,7 +48,7 @@ class FloodfillStoreJob extends StoreJob {
_facade = facade; _facade = facade;
} }
protected int getParallelization() { return 2; } protected int getParallelization() { return 1; }
protected int getRedundancy() { return 1; } protected int getRedundancy() { return 1; }
/** /**

View File

@ -689,6 +689,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
+ routerInfo.getOptions().size() + " options on " + routerInfo.getOptions().size() + " options on "
+ new Date(routerInfo.getPublished())); + new Date(routerInfo.getPublished()));
_context.peerManager().setCapabilities(key, routerInfo.getCapabilities());
_ds.put(key, routerInfo); _ds.put(key, routerInfo);
synchronized (_lastSent) { synchronized (_lastSent) {
if (!_lastSent.containsKey(key)) if (!_lastSent.containsKey(key))
@ -721,6 +722,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
return; return;
} }
_context.peerManager().removeCapabilities(dbEntry);
boolean removed = _kb.remove(dbEntry); boolean removed = _kb.remove(dbEntry);
if (removed) { if (removed) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
@ -737,6 +739,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
if (o == null) { if (o == null) {
boolean removed = _kb.remove(dbEntry); boolean removed = _kb.remove(dbEntry);
_context.peerManager().removeCapabilities(dbEntry);
// if we dont know the key, lets make sure it isn't a now-dead peer // if we dont know the key, lets make sure it isn't a now-dead peer
} }

View File

@ -52,7 +52,7 @@ class SearchJob extends JobImpl {
private boolean _deferredCleared; private boolean _deferredCleared;
private long _startedOn; private long _startedOn;
private static final int SEARCH_BREDTH = 10; // 10 peers at a time private static final int SEARCH_BREDTH = 3; // 10 peers at a time
private static final int SEARCH_PRIORITY = 400; // large because the search is probably for a real search private static final int SEARCH_PRIORITY = 400; // large because the search is probably for a real search
/** only send the 10 closest "dont tell me about" refs */ /** only send the 10 closest "dont tell me about" refs */
static final int MAX_CLOSEST = 10; static final int MAX_CLOSEST = 10;

View File

@ -10,11 +10,7 @@ package net.i2p.router.peermanager;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList; import java.util.*;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.router.PeerSelectionCriteria; import net.i2p.router.PeerSelectionCriteria;
@ -30,6 +26,8 @@ class PeerManager {
private RouterContext _context; private RouterContext _context;
private ProfileOrganizer _organizer; private ProfileOrganizer _organizer;
private ProfilePersistenceHelper _persistenceHelper; private ProfilePersistenceHelper _persistenceHelper;
private List _peersByCapability[];
private Map _capabilitiesByPeer;
public PeerManager(RouterContext context) { public PeerManager(RouterContext context) {
_context = context; _context = context;
@ -37,6 +35,10 @@ class PeerManager {
_persistenceHelper = new ProfilePersistenceHelper(context); _persistenceHelper = new ProfilePersistenceHelper(context);
_organizer = context.profileOrganizer(); _organizer = context.profileOrganizer();
_organizer.setUs(context.routerHash()); _organizer.setUs(context.routerHash());
_capabilitiesByPeer = new HashMap(128);
_peersByCapability = new List[26];
for (int i = 0; i < _peersByCapability.length; i++)
_peersByCapability[i] = new ArrayList(64);
loadProfiles(); loadProfiles();
_context.jobQueue().addJob(new EvaluateProfilesJob(_context)); _context.jobQueue().addJob(new EvaluateProfilesJob(_context));
//_context.jobQueue().addJob(new PersistProfilesJob(_context, this)); //_context.jobQueue().addJob(new PersistProfilesJob(_context, this));
@ -116,6 +118,86 @@ class PeerManager {
return new ArrayList(peers); return new ArrayList(peers);
} }
public void setCapabilities(Hash peer, String caps) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Setting capabilities for " + peer.toBase64() + " to " + caps);
if (caps != null) caps = caps.toLowerCase();
synchronized (_capabilitiesByPeer) {
String oldCaps = null;
if (caps != null)
oldCaps = (String)_capabilitiesByPeer.put(peer, caps);
else
oldCaps = (String)_capabilitiesByPeer.remove(peer);
if (oldCaps != null) {
for (int i = 0; i < oldCaps.length(); i++) {
char c = oldCaps.charAt(i);
if ( (caps == null) || (caps.indexOf(c) < 0) ) {
List peers = locked_getPeers(c);
if (peers != null)
peers.remove(peer);
}
}
}
if (caps != null) {
for (int i = 0; i < caps.length(); i++) {
char c = caps.charAt(i);
if ( (oldCaps != null) && (oldCaps.indexOf(c) >= 0) )
continue;
List peers = locked_getPeers(c);
if ( (peers != null) && (!peers.contains(peer)) )
peers.add(peer);
}
}
}
}
private List locked_getPeers(char c) {
c = Character.toLowerCase(c);
int i = c - 'a';
if ( (i < 0) || (i >= _peersByCapability.length) ) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Invalid capability " + c + " (" + i + ")");
return null;
}
return _peersByCapability[i];
}
public void removeCapabilities(Hash peer) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Removing capabilities from " + peer.toBase64());
synchronized (_capabilitiesByPeer) {
String oldCaps = (String)_capabilitiesByPeer.remove(peer);
if (oldCaps != null) {
for (int i = 0; i < oldCaps.length(); i++) {
char c = oldCaps.charAt(i);
List peers = locked_getPeers(c);
if (peers != null)
peers.remove(peer);
}
}
}
}
public Hash selectRandomByCapability(char capability) {
int index = _context.random().nextInt(Integer.MAX_VALUE);
synchronized (_capabilitiesByPeer) {
List peers = locked_getPeers(capability);
if ( (peers != null) && (peers.size() > 0) ) {
index = index % peers.size();
return (Hash)peers.get(index);
}
}
return null;
}
public List getPeersByCapability(char capability) {
synchronized (_capabilitiesByPeer) {
List peers = locked_getPeers(capability);
if (peers != null)
return new ArrayList(peers);
}
return null;
}
public void renderStatusHTML(Writer out) throws IOException { public void renderStatusHTML(Writer out) throws IOException {
_organizer.renderStatusHTML(out); _organizer.renderStatusHTML(out);
} }

View File

@ -10,8 +10,10 @@ package net.i2p.router.peermanager;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.i2p.data.Hash;
import net.i2p.router.PeerManagerFacade; import net.i2p.router.PeerManagerFacade;
import net.i2p.router.PeerSelectionCriteria; import net.i2p.router.PeerSelectionCriteria;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
@ -58,7 +60,25 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade {
return _manager.selectPeers(criteria); return _manager.selectPeers(criteria);
} }
public void setCapabilities(Hash peer, String caps) {
if (_manager == null) return;
_manager.setCapabilities(peer, caps);
}
public void removeCapabilities(Hash peer) {
if (_manager == null) return;
_manager.removeCapabilities(peer);
}
public Hash selectRandomByCapability(char capability) {
if (_manager == null) return null;
return _manager.selectRandomByCapability(capability);
}
public List getPeersByCapability(char capability) {
if (_manager == null) return new ArrayList(0);
return _manager.getPeersByCapability(capability);
}
public void renderStatusHTML(Writer out) throws IOException { public void renderStatusHTML(Writer out) throws IOException {
_manager.renderStatusHTML(out); _manager.renderStatusHTML(out);
} }
} }

View File

@ -56,6 +56,7 @@ public class CreateRouterInfoJob extends JobImpl {
stats.setProperty(RouterInfo.PROP_NETWORK_ID, Router.NETWORK_ID+""); stats.setProperty(RouterInfo.PROP_NETWORK_ID, Router.NETWORK_ID+"");
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext()))
info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
getContext().router().addReachabilityCapability(info);
info.setOptions(stats); info.setOptions(stats);
info.setPeers(new HashSet()); info.setPeers(new HashSet());
info.setPublished(getCurrentPublishDate(getContext())); info.setPublished(getCurrentPublishDate(getContext()));

View File

@ -129,6 +129,7 @@ public class RebuildRouterInfoJob extends JobImpl {
info.setOptions(stats); info.setOptions(stats);
if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) if (FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext()))
info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); info.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL);
getContext().router().addReachabilityCapability(info);
// info.setPeers(new HashSet()); // this would have the trusted peers // info.setPeers(new HashSet()); // this would have the trusted peers
info.setPublished(CreateRouterInfoJob.getCurrentPublishDate(getContext())); info.setPublished(CreateRouterInfoJob.getCurrentPublishDate(getContext()));

View File

@ -75,7 +75,10 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
return _manager.getMostRecentErrorMessages(); return _manager.getMostRecentErrorMessages();
} }
public short getReachabilityStatus() { return _manager.getReachabilityStatus(); } public short getReachabilityStatus() {
if (_manager == null) return CommSystemFacade.STATUS_UNKNOWN;
return _manager.getReachabilityStatus();
}
public void recheckReachability() { _manager.recheckReachability(); } public void recheckReachability() { _manager.recheckReachability(); }
public void renderStatusHTML(Writer out) throws IOException { public void renderStatusHTML(Writer out) throws IOException {

View File

@ -9,14 +9,7 @@ import java.io.Writer;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import net.i2p.data.Base64; import net.i2p.data.Base64;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
@ -250,7 +243,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_refiller.startup(); _refiller.startup();
_flooder.startup(); _flooder.startup();
_expireEvent.setIsAlive(true); _expireEvent.setIsAlive(true);
_testEvent.setIsAlive(true); _testEvent.setIsAlive(true); // this queues it for 3-6 minutes in the future...
SimpleTimer.getInstance().addEvent(_testEvent, 10*1000); // lets requeue it for Real Soon
} }
public void shutdown() { public void shutdown() {
@ -832,19 +826,33 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return active; return active;
} }
private static class AlphaComparator implements Comparator {
private static final AlphaComparator _instance = new AlphaComparator();
public static final AlphaComparator instance() { return _instance; }
public int compare(Object lhs, Object rhs) {
if ( (lhs == null) || (rhs == null) || !(lhs instanceof PeerState) || !(rhs instanceof PeerState))
throw new IllegalArgumentException("rhs = " + rhs + " lhs = " + lhs);
PeerState l = (PeerState)lhs;
PeerState r = (PeerState)rhs;
// base64 retains binary ordering
return DataHelper.compareTo(l.getRemotePeer().getData(), r.getRemotePeer().getData());
}
}
public void renderStatusHTML(Writer out) throws IOException { public void renderStatusHTML(Writer out) throws IOException {
List peers = null; TreeSet peers = new TreeSet(AlphaComparator.instance());
synchronized (_peersByIdent) { synchronized (_peersByIdent) {
peers = new ArrayList(_peersByIdent.values()); peers.addAll(_peersByIdent.values());
} }
long offsetTotal = 0; long offsetTotal = 0;
StringBuffer buf = new StringBuffer(512); StringBuffer buf = new StringBuffer(512);
buf.append("<b>UDP connections: ").append(peers.size()).append("</b><br />\n"); buf.append("<b>UDP connections: ").append(peers.size()).append("</b><br />\n");
buf.append("<table border=\"1\">\n"); buf.append("<table border=\"1\">\n");
buf.append(" <tr><td><b>peer</b></td><td><b>activity (in/out)</b></td>"); buf.append(" <tr><td><b>peer</b></td><td><b>idle</b></td>");
buf.append(" <td><b>transfer (in/out)</b></td>\n"); buf.append(" <td><b>in/out</b></td>\n");
buf.append(" <td><b>uptime</b></td><td><b>skew</b></td>\n"); buf.append(" <td><b>up</b></td><td><b>skew</b></td>\n");
buf.append(" <td><b>cwnd</b></td><td><b>ssthresh</b></td>\n"); buf.append(" <td><b>cwnd</b></td><td><b>ssthresh</b></td>\n");
buf.append(" <td><b>rtt</b></td><td><b>dev</b></td><td><b>rto</b></td>\n"); buf.append(" <td><b>rtt</b></td><td><b>dev</b></td><td><b>rto</b></td>\n");
buf.append(" <td><b>send</b></td><td><b>recv</b></td>\n"); buf.append(" <td><b>send</b></td><td><b>recv</b></td>\n");
@ -853,42 +861,67 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
out.write(buf.toString()); out.write(buf.toString());
buf.setLength(0); buf.setLength(0);
long now = _context.clock().now(); long now = _context.clock().now();
for (int i = 0; i < peers.size(); i++) { for (Iterator iter = peers.iterator(); iter.hasNext(); ) {
PeerState peer = (PeerState)peers.get(i); PeerState peer = (PeerState)iter.next();
if (now-peer.getLastReceiveTime() > 60*60*1000) if (now-peer.getLastReceiveTime() > 60*60*1000)
continue; // don't include old peers continue; // don't include old peers
buf.append("<tr>"); buf.append("<tr>");
String name = peer.getRemotePeer().toBase64().substring(0,6); String name = peer.getRemotePeer().toBase64().substring(0,6);
buf.append("<td nowrap>"); buf.append("<td valign=\"top\" nowrap><code>");
buf.append("<a href=\"netdb.jsp#"); buf.append("<a href=\"netdb.jsp#");
buf.append(name); buf.append(name);
buf.append("\">"); buf.append("\">");
buf.append(name).append("@"); buf.append(name).append("@");
byte ip[] = peer.getRemoteIP(); byte ip[] = peer.getRemoteIP();
for (int j = 0; j < ip.length; j++) { for (int j = 0; j < ip.length; j++) {
buf.append(ip[j] & 0xFF); int num = ip[j] & 0xFF;
if (num < 10)
buf.append("00");
else if (num < 100)
buf.append("0");
buf.append(num);
if (j + 1 < ip.length) if (j + 1 < ip.length)
buf.append('.'); buf.append('.');
} }
buf.append(':').append(peer.getRemotePort()); buf.append(':');
int port = peer.getRemotePort();
if (port < 10)
buf.append("0000");
else if (port < 100)
buf.append("000");
else if (port < 1000)
buf.append("00");
else if (port < 10000)
buf.append("0");
buf.append(port);
buf.append("</a>"); buf.append("</a>");
if (_activeThrottle.isChoked(peer.getRemotePeer())) boolean appended = false;
if (_activeThrottle.isChoked(peer.getRemotePeer())) {
if (!appended) buf.append("<br />");
buf.append(" [choked]"); buf.append(" [choked]");
if (peer.getConsecutiveFailedSends() > 0) appended = true;
}
if (peer.getConsecutiveFailedSends() > 0) {
if (!appended) buf.append("<br />");
buf.append(" [").append(peer.getConsecutiveFailedSends()).append(" failures]"); buf.append(" [").append(peer.getConsecutiveFailedSends()).append(" failures]");
if (_context.shitlist().isShitlisted(peer.getRemotePeer())) appended = true;
}
if (_context.shitlist().isShitlisted(peer.getRemotePeer())) {
if (!appended) buf.append("<br />");
buf.append(" [shitlisted]"); buf.append(" [shitlisted]");
buf.append("</td>"); appended = true;
}
buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append((now-peer.getLastReceiveTime())/1000); buf.append((now-peer.getLastReceiveTime())/1000);
buf.append("s/"); buf.append("s/");
buf.append((now-peer.getLastSendTime())/1000); buf.append((now-peer.getLastSendTime())/1000);
buf.append("s</td>"); buf.append("s</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(formatKBps(peer.getReceiveBps())); buf.append(formatKBps(peer.getReceiveBps()));
buf.append("KBps/"); buf.append("KBps/");
buf.append(formatKBps(peer.getSendBps())); buf.append(formatKBps(peer.getSendBps()));
@ -897,60 +930,60 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
//buf.append("KBps/"); //buf.append("KBps/");
//buf.append(formatKBps(peer.getSendACKBps())); //buf.append(formatKBps(peer.getSendACKBps()));
//buf.append("KBps "); //buf.append("KBps ");
buf.append("</td>"); buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(DataHelper.formatDuration(now-peer.getKeyEstablishedTime())); buf.append(DataHelper.formatDuration(now-peer.getKeyEstablishedTime()));
buf.append("</td>"); buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getClockSkew()/1000); buf.append(peer.getClockSkew()/1000);
buf.append("s</td>"); buf.append("s</code></td>");
offsetTotal = offsetTotal + peer.getClockSkew(); offsetTotal = offsetTotal + peer.getClockSkew();
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getSendWindowBytes()/1024); buf.append(peer.getSendWindowBytes()/1024);
buf.append("K</td>"); buf.append("K</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getSlowStartThreshold()/1024); buf.append(peer.getSlowStartThreshold()/1024);
buf.append("K</td>"); buf.append("K</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getRTT()); buf.append(peer.getRTT());
buf.append("</td>"); buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getRTTDeviation()); buf.append(peer.getRTTDeviation());
buf.append("</td>"); buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getRTO()); buf.append(peer.getRTO());
buf.append("</td>"); buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getPacketsTransmitted()); buf.append(peer.getPacketsTransmitted());
buf.append("</td>"); buf.append("</code></td>");
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(peer.getPacketsReceived()); buf.append(peer.getPacketsReceived());
buf.append("</td>"); buf.append("</code></td>");
double sent = (double)peer.getPacketsPeriodTransmitted(); double sent = (double)peer.getPacketsPeriodTransmitted();
double sendLostPct = 0; double sendLostPct = 0;
if (sent > 0) if (sent > 0)
sendLostPct = (double)peer.getPacketsRetransmitted()/(sent); sendLostPct = (double)peer.getPacketsRetransmitted()/(sent);
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
//buf.append(formatPct(sendLostPct)); //buf.append(formatPct(sendLostPct));
buf.append(peer.getPacketsRetransmitted()); // + "/" + peer.getPacketsPeriodRetransmitted() + "/" + sent); buf.append(peer.getPacketsRetransmitted()); // + "/" + peer.getPacketsPeriodRetransmitted() + "/" + sent);
//buf.append(peer.getPacketRetransmissionRate()); //buf.append(peer.getPacketRetransmissionRate());
buf.append("</td>"); buf.append("</code></td>");
double recvDupPct = (double)peer.getPacketsReceivedDuplicate()/(double)peer.getPacketsReceived(); double recvDupPct = (double)peer.getPacketsReceivedDuplicate()/(double)peer.getPacketsReceived();
buf.append("<td>"); buf.append("<td valign=\"top\" ><code>");
buf.append(formatPct(recvDupPct)); buf.append(formatPct(recvDupPct));
buf.append("</td>"); buf.append("</code></td>");
buf.append("</tr>"); buf.append("</tr>");
out.write(buf.toString()); out.write(buf.toString());

View File

@ -1,9 +1,6 @@
package net.i2p.router.tunnel.pool; package net.i2p.router.tunnel.pool;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
@ -22,7 +19,8 @@ class ClientPeerSelector extends TunnelPeerSelector {
if (shouldSelectExplicit(settings)) if (shouldSelectExplicit(settings))
return selectExplicit(ctx, settings, length); return selectExplicit(ctx, settings, length);
ctx.profileOrganizer().selectFastPeers(length, null, matches); Set exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory());
ctx.profileOrganizer().selectFastPeers(length, exclude, matches);
matches.remove(ctx.routerHash()); matches.remove(ctx.routerHash());
ArrayList rv = new ArrayList(matches); ArrayList rv = new ArrayList(matches);

View File

@ -1,9 +1,6 @@
package net.i2p.router.tunnel.pool; package net.i2p.router.tunnel.pool;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
import net.i2p.util.Log; import net.i2p.util.Log;
@ -30,7 +27,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
return rv; return rv;
} }
HashSet exclude = new HashSet(1); Set exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory());
exclude.add(ctx.routerHash()); exclude.add(ctx.routerHash());
HashSet matches = new HashSet(length); HashSet matches = new HashSet(length);
ctx.profileOrganizer().selectNotFailingPeers(length, exclude, matches, false); ctx.profileOrganizer().selectNotFailingPeers(length, exclude, matches, false);

View File

@ -1,12 +1,9 @@
package net.i2p.router.tunnel.pool; package net.i2p.router.tunnel.pool;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.router.Router;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
import net.i2p.util.Log; import net.i2p.util.Log;
@ -114,4 +111,47 @@ abstract class TunnelPeerSelector {
log.info(toString() + ": Selecting peers explicitly: " + rv); log.info(toString() + ": Selecting peers explicitly: " + rv);
return rv; return rv;
} }
/**
* Pick peers that we want to avoid
*/
public Set getExclude(RouterContext ctx, boolean isInbound, boolean isExploratory) {
if (filterUnreachable(ctx, isInbound, isExploratory)) {
List caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);
if (caps == null) return new HashSet(0);
HashSet rv = new HashSet(caps);
return rv;
} else {
return new HashSet(1);
}
}
private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.outboundExploratoryExcludeUnreachable";
private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.outboundClientExcludeUnreachable";
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable";
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable";
private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false;
private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false;
private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false;
private static final boolean DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = false;
protected boolean filterUnreachable(RouterContext ctx, boolean isInbound, boolean isExploratory) {
boolean def = false;
String val = null;
if (isExploratory)
if (isInbound)
val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
else
val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
else
if (isInbound)
val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE);
else
val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE);
boolean rv = (val != null ? Boolean.valueOf(val).booleanValue() : def);
//System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory);
return rv;
}
} }