* SSU/Reachability:

- Extend shitlist time from 4-8m to 40-60m
      - Add some shitlist logging
      - Don't shitlist twice when unreachable on all transports
      - Exclude netDb-listed unreachable peers from inbound tunnels;
        this won't help much since there are very few of these now
      - Remove 10s delay on inbound UDP connections used for the
        0.6.1.10 transition
      - Track and display UDP connection direction on peers.jsp
      - Show shitlist status in-line on profiles.jsp
This commit is contained in:
zzz
2008-04-16 20:51:57 +00:00
parent 5ba1e458c6
commit 2edd84e088
9 changed files with 83 additions and 31 deletions

View File

@ -1,3 +1,15 @@
2008-04-16 zzz
* SSU/Reachability:
- Extend shitlist time from 4-8m to 40-60m
- Add some shitlist logging
- Don't shitlist twice when unreachable on all transports
- Exclude netDb-listed unreachable peers from inbound tunnels;
this won't help much since there are very few of these now
- Remove 10s delay on inbound UDP connections used for the
0.6.1.10 transition
- Track and display UDP connection direction on peers.jsp
- Show shitlist status in-line on profiles.jsp
2008-04-15 zzz 2008-04-15 zzz
* SSU Reachability/PeerTestManager: * SSU Reachability/PeerTestManager:
- Back out strict peer ordering until we fix SSU - Back out strict peer ordering until we fix SSU

View File

@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion { public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $"; public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $";
public final static String VERSION = "0.6.1.32"; public final static String VERSION = "0.6.1.32";
public final static long BUILD = 17; public final static long BUILD = 18;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -37,7 +37,7 @@ public class Shitlist {
Set transports; Set transports;
} }
public final static long SHITLIST_DURATION_MS = 4*60*1000; // 4 minute shitlist public final static long SHITLIST_DURATION_MS = 40*60*1000; // 40 minute shitlist
public Shitlist(RouterContext context) { public Shitlist(RouterContext context) {
_context = context; _context = context;
@ -72,6 +72,8 @@ public class Shitlist {
if (prof != null) if (prof != null)
prof.unshitlist(); prof.unshitlist();
_context.messageHistory().unshitlist(peer); _context.messageHistory().unshitlist(peer);
if (_log.shouldLog(Log.INFO))
_log.info("Unshitlisting router (expired) " + peer.toBase64());
} }
requeue(30*1000); requeue(30*1000);
@ -152,12 +154,13 @@ public class Shitlist {
public void unshitlistRouter(Hash peer, String transport) { unshitlistRouter(peer, true, transport); } public void unshitlistRouter(Hash peer, String transport) { unshitlistRouter(peer, true, transport); }
private void unshitlistRouter(Hash peer, boolean realUnshitlist, String transport) { private void unshitlistRouter(Hash peer, boolean realUnshitlist, String transport) {
if (peer == null) return; if (peer == null) return;
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.DEBUG))
_log.info("Unshitlisting router " + peer.toBase64() _log.debug("Calling unshitlistRouter " + peer.toBase64()
+ (transport != null ? "/" + transport : "")); + (transport != null ? "/" + transport : ""));
boolean fully = false; boolean fully = false;
Entry e;
synchronized (_entries) { synchronized (_entries) {
Entry e = (Entry)_entries.remove(peer); e = (Entry)_entries.remove(peer);
if ( (e == null) || (e.transports == null) || (transport == null) || (e.transports.size() <= 1) ) { if ( (e == null) || (e.transports == null) || (transport == null) || (e.transports.size() <= 1) ) {
// fully unshitlisted // fully unshitlisted
fully = true; fully = true;
@ -176,6 +179,9 @@ public class Shitlist {
prof.unshitlist(); prof.unshitlist();
} }
_context.messageHistory().unshitlist(peer); _context.messageHistory().unshitlist(peer);
if (_log.shouldLog(Log.INFO) && e != null)
_log.info("Unshitlisting router " + peer.toBase64()
+ (transport != null ? "/" + transport : ""));
} }
} }
@ -209,6 +215,8 @@ public class Shitlist {
if (prof != null) if (prof != null)
prof.unshitlist(); prof.unshitlist();
_context.messageHistory().unshitlist(peer); _context.messageHistory().unshitlist(peer);
if (_log.shouldLog(Log.INFO))
_log.info("Unshitlisting router (expired) " + peer.toBase64());
} }
return rv; return rv;

View File

@ -134,7 +134,10 @@ class ProfileOrganizerRenderer {
buf.append("</td>"); buf.append("</td>");
buf.append("<td align=\"right\">").append(num(prof.getCapacityValue())).append("</td>"); buf.append("<td align=\"right\">").append(num(prof.getCapacityValue())).append("</td>");
buf.append("<td align=\"right\">").append(num(prof.getIntegrationValue())).append("</td>"); buf.append("<td align=\"right\">").append(num(prof.getIntegrationValue())).append("</td>");
buf.append("<td align=\"right\">").append(prof.getIsFailing()).append("</td>"); buf.append("<td>");
if (_context.shitlist().isShitlisted(peer)) buf.append("Shitlist");
if (prof.getIsFailing()) buf.append(" Failing");
buf.append("&nbsp</td>");
//buf.append("<td><a href=\"/profile/").append(prof.getPeer().toBase64().substring(0, 32)).append("\">profile.txt</a> "); //buf.append("<td><a href=\"/profile/").append(prof.getPeer().toBase64().substring(0, 32)).append("\">profile.txt</a> ");
//buf.append(" <a href=\"#").append(prof.getPeer().toBase64().substring(0, 32)).append("\">netDb</a></td>"); //buf.append(" <a href=\"#").append(prof.getPeer().toBase64().substring(0, 32)).append("\">netDb</a></td>");
buf.append("<td nowrap><a href=\"netdb.jsp#").append(peer.toBase64().substring(0,6)).append("\">netDb</a>"); buf.append("<td nowrap><a href=\"netdb.jsp#").append(peer.toBase64().substring(0,6)).append("\">netDb</a>");

View File

@ -259,6 +259,9 @@ public class TransportManager implements TransportEventListener {
Transport t = (Transport)_transports.get(i); Transport t = (Transport)_transports.get(i);
if (t.isUnreachable(peer)) { if (t.isUnreachable(peer)) {
unreachableTransports++; unreachableTransports++;
// this keeps GetBids() from shitlisting for "no common transports"
// right after we shitlisted for "unreachable on any transport" below...
msg.transportFailed(t.getStyle());
continue; continue;
} }
if (failedTransports.contains(t.getStyle())) { if (failedTransports.contains(t.getStyle())) {

View File

@ -431,6 +431,7 @@ public class EstablishmentManager {
peer.setRemotePeer(remote.calculateHash()); peer.setRemotePeer(remote.calculateHash());
peer.setWeRelayToThemAs(state.getSentRelayTag()); peer.setWeRelayToThemAs(state.getSentRelayTag());
peer.setTheyRelayToUsAs(0); peer.setTheyRelayToUsAs(0);
peer.setInbound();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle completely established (inbound): " + state.getRemoteHostId().toString() _log.debug("Handle completely established (inbound): " + state.getRemoteHostId().toString()
@ -451,9 +452,16 @@ public class EstablishmentManager {
* dont send our info immediately, just send a small data packet, and 5-10s later, * dont send our info immediately, just send a small data packet, and 5-10s later,
* if the peer isnt shitlisted, *then* send them our info. this will help kick off * if the peer isnt shitlisted, *then* send them our info. this will help kick off
* the oldnet * the oldnet
* The "oldnet" was < 0.6.1.10, it is long gone.
* The delay really slows down the network.
* The peer is unshitlisted and marked reachable by addRemotePeerState() which calls markReachable()
* so the check below is fairly pointless.
* If for some strange reason an oldnet router (NETWORK_ID == 1) does show up,
* it's handled in UDPTransport.messageReceived()
* (where it will get dropped, marked unreachable and shitlisted at that time).
*/ */
private void sendInboundComplete(PeerState peer) { private void sendInboundComplete(PeerState peer) {
SimpleTimer.getInstance().addEvent(new PublishToNewInbound(peer), 10*1000); // SimpleTimer.getInstance().addEvent(new PublishToNewInbound(peer), 10*1000);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Completing to the peer after confirm: " + peer); _log.info("Completing to the peer after confirm: " + peer);
DeliveryStatusMessage dsm = new DeliveryStatusMessage(_context); DeliveryStatusMessage dsm = new DeliveryStatusMessage(_context);
@ -461,6 +469,7 @@ public class EstablishmentManager {
dsm.setMessageExpiration(_context.clock().now()+10*1000); dsm.setMessageExpiration(_context.clock().now()+10*1000);
dsm.setMessageId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE)); dsm.setMessageId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
_transport.send(dsm, peer); _transport.send(dsm, peer);
SimpleTimer.getInstance().addEvent(new PublishToNewInbound(peer), 0);
} }
private class PublishToNewInbound implements SimpleTimer.TimedEvent { private class PublishToNewInbound implements SimpleTimer.TimedEvent {
private PeerState _peer; private PeerState _peer;

View File

@ -190,7 +190,9 @@ public class PeerState {
private volatile int _concurrentMessagesActive = 0; private volatile int _concurrentMessagesActive = 0;
/** how many concurrency rejections have we had in a row */ /** how many concurrency rejections have we had in a row */
private volatile int _consecutiveRejections = 0; private volatile int _consecutiveRejections = 0;
/** is it inbound? **/
private boolean _isInbound;
private static final int DEFAULT_SEND_WINDOW_BYTES = 8*1024; private static final int DEFAULT_SEND_WINDOW_BYTES = 8*1024;
private static final int MINIMUM_WINDOW_BYTES = DEFAULT_SEND_WINDOW_BYTES; private static final int MINIMUM_WINDOW_BYTES = DEFAULT_SEND_WINDOW_BYTES;
private static final int MAX_SEND_WINDOW_BYTES = 1024*1024; private static final int MAX_SEND_WINDOW_BYTES = 1024*1024;
@ -268,6 +270,7 @@ public class PeerState {
_inboundMessages = new HashMap(8); _inboundMessages = new HashMap(8);
_outboundMessages = new ArrayList(32); _outboundMessages = new ArrayList(32);
_dead = false; _dead = false;
_isInbound = false;
_context.statManager().createRateStat("udp.congestionOccurred", "How large the cwin was when congestion occurred (duration == sendBps)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 }); _context.statManager().createRateStat("udp.congestionOccurred", "How large the cwin was when congestion occurred (duration == sendBps)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.congestedRTO", "retransmission timeout after congestion (duration == rtt dev)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 }); _context.statManager().createRateStat("udp.congestedRTO", "retransmission timeout after congestion (duration == rtt dev)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.sendACKPartial", "Number of partial ACKs sent (duration == number of full ACKs in that ack packet)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 }); _context.statManager().createRateStat("udp.sendACKPartial", "Number of partial ACKs sent (duration == number of full ACKs in that ack packet)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
@ -553,6 +556,8 @@ public class PeerState {
public int getConcurrentSends() { return _concurrentMessagesActive; } public int getConcurrentSends() { return _concurrentMessagesActive; }
public int getConcurrentSendWindow() { return _concurrentMessagesAllowed; } public int getConcurrentSendWindow() { return _concurrentMessagesAllowed; }
public int getConsecutiveSendRejections() { return _consecutiveRejections; } public int getConsecutiveSendRejections() { return _consecutiveRejections; }
public boolean isInbound() { return _isInbound; }
public void setInbound() { _isInbound = true; }
/** we received the message specified completely */ /** we received the message specified completely */
public void messageFullyReceived(Long messageId, int bytes) { messageFullyReceived(messageId, bytes, false); } public void messageFullyReceived(Long messageId, int bytes) { messageFullyReceived(messageId, bytes, false); }

View File

@ -625,6 +625,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} }
} }
markUnreachable(peerHash); markUnreachable(peerHash);
_context.shitlist().shitlistRouter(peerHash, "Part of the wrong network");
//_context.shitlist().shitlistRouter(peerHash, "Part of the wrong network", STYLE); //_context.shitlist().shitlistRouter(peerHash, "Part of the wrong network", STYLE);
dropPeer(peerHash, false, "wrong network"); dropPeer(peerHash, false, "wrong network");
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
@ -1673,14 +1674,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
buf.append(port); buf.append(port);
*/ */
buf.append("</a>&nbsp;"); buf.append("</a>&nbsp;");
if (peer.isInbound())
buf.append("&gt; ");
else
buf.append("&lt; ");
if (peer.getWeRelayToThemAs() > 0) if (peer.getWeRelayToThemAs() > 0)
buf.append("&gt;"); buf.append("^");
else else
buf.append("&nbsp;"); buf.append("&nbsp;");
if (peer.getTheyRelayToUsAs() > 0) if (peer.getTheyRelayToUsAs() > 0)
buf.append("&lt;"); buf.append("v");
else
buf.append("&nbsp;");
boolean appended = false; boolean appended = false;
if (_activeThrottle.isChoked(peer.getRemotePeer())) { if (_activeThrottle.isChoked(peer.getRemotePeer())) {
@ -1872,7 +1875,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} }
private static final String KEY = "<tr><td colspan=\"15\" valign=\"top\" align=\"left\">" + private static final String KEY = "<tr><td colspan=\"15\" valign=\"top\" align=\"left\">" +
"<b id=\"def.peer\">peer</b>: the remote peer (&lt; means they offer to introduce us, &gt; means we offer to introduce them)<br />\n" + "<b id=\"def.peer\">peer</b>: the remote peer (&lt; inbound, &gt; outbound, v means they offer to introduce us, ^ means we offer to introduce them)<br />\n" +
"<b id=\"def.idle\">idle</b>: the idle time is how long since a packet has been received or sent<br />\n" + "<b id=\"def.idle\">idle</b>: the idle time is how long since a packet has been received or sent<br />\n" +
"<b id=\"def.rate\">in/out</b>: the rates show a smoothed inbound and outbound transfer rate (KBytes per second)<br />\n" + "<b id=\"def.rate\">in/out</b>: the rates show a smoothed inbound and outbound transfer rate (KBytes per second)<br />\n" +
"<b id=\"def.up\">up</b>: the uptime is how long ago this session was established<br />\n" + "<b id=\"def.up\">up</b>: the uptime is how long ago this session was established<br />\n" +

View File

@ -152,16 +152,26 @@ public abstract class TunnelPeerSelector {
// isn't safe, since they may publish one set of routerInfo to us and another to // isn't safe, since they may publish one set of routerInfo to us and another to
// other peers. the defaults for filterUnreachable has always been to return false, // other peers. the defaults for filterUnreachable has always been to return false,
// but might as well make it explicit with a "false &&" // but might as well make it explicit with a "false &&"
//
if (false && filterUnreachable(ctx, isInbound, isExploratory)) { // Unreachable peers at the inbound gateway is a major cause of problems.
// Due to a bug in SSU peer testing in 0.6.1.32 and earlier, peers don't know
// if they are unreachable, so this won't help much. As of 0.6.1.33 we should have
// lots of unreachables, so enable this for now.
// We could just try and exclude them as the inbound gateway but that's harder
// (and even worse for anonymity?).
//
// Defaults changed to true for inbound only in filterUnreachable below.
Set peers = new HashSet(1);
// if (false && filterUnreachable(ctx, isInbound, isExploratory)) {
if (filterUnreachable(ctx, isInbound, isExploratory)) {
List caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE); List caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);
if (caps == null) return new HashSet(0); if (caps != null)
HashSet rv = new HashSet(caps); peers.addAll(caps);
return rv; }
} else if (filterSlow(ctx, isInbound, isExploratory)) { if (filterSlow(ctx, isInbound, isExploratory)) {
Log log = ctx.logManager().getLog(TunnelPeerSelector.class); Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
char excl[] = getExcludeCaps(ctx); char excl[] = getExcludeCaps(ctx);
Set peers = new HashSet(1);
if (excl != null) { if (excl != null) {
FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb(); FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb();
List known = fac.getKnownRouterData(); List known = fac.getKnownRouterData();
@ -268,10 +278,8 @@ public abstract class TunnelPeerSelector {
} }
*/ */
} }
return peers;
} else {
return new HashSet(1);
} }
return peers;
} }
public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) { public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) {
@ -375,10 +383,11 @@ public abstract class TunnelPeerSelector {
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable"; 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 String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable";
private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; private static final String DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "false";
private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; private static final String DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = "false";
private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; // see comments at getExclude() above
private static final boolean DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; private static final String DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "true";
private static final String DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "true";
protected boolean filterUnreachable(RouterContext ctx, boolean isInbound, boolean isExploratory) { protected boolean filterUnreachable(RouterContext ctx, boolean isInbound, boolean isExploratory) {
boolean def = false; boolean def = false;
@ -386,14 +395,14 @@ public abstract class TunnelPeerSelector {
if (isExploratory) if (isExploratory)
if (isInbound) if (isInbound)
val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE); val = ctx.getProperty(PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
else else
val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE); val = ctx.getProperty(PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE);
else else
if (isInbound) if (isInbound)
val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE); val = ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE);
else else
val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE); val = ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE);
boolean rv = (val != null ? Boolean.valueOf(val).booleanValue() : def); boolean rv = (val != null ? Boolean.valueOf(val).booleanValue() : def);
//System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory); //System.err.println("Filter unreachable? " + rv + " (inbound? " + isInbound + ", exploratory? " + isExploratory);