From bc7bd628dbae736f7f1c05c40453553203c9e9aa Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 26 Feb 2008 19:33:11 +0000 Subject: [PATCH] * Reintroduce NTCP backlog pushback, with switch back to previous tunnel when no longer backlogged * Catch an nio exception in an NTCP logging statement if loglevel is WARN * IRC Proxy: terminate all messages with \r\n (thanks TrivialPursuit!) --- .../net/i2p/i2ptunnel/I2PTunnelIRCClient.java | 4 +- history.txt | 6 ++ .../src/net/i2p/router/RouterVersion.java | 2 +- .../OutboundClientMessageOneShotJob.java | 73 +++++++++++++++---- .../router/transport/ntcp/NTCPConnection.java | 4 +- 5 files changed, 70 insertions(+), 19 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index 2e85057c4..7a24e3995 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -164,7 +164,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable if (_log.shouldLog(Log.INFO)) _log.info("inbound: "+outmsg); } - outmsg=outmsg+"\n"; + outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3 output.write(outmsg.getBytes("ISO-8859-1")); } else { if (_log.shouldLog(Log.WARN)) @@ -238,7 +238,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable if (_log.shouldLog(Log.INFO)) _log.info("outbound: "+outmsg); } - outmsg=outmsg+"\n"; + outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3 output.write(outmsg.getBytes("ISO-8859-1")); } else { if (_log.shouldLog(Log.WARN)) diff --git a/history.txt b/history.txt index ae51b4c4a..34ca15a92 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,9 @@ +2008-02-26 zzz + * Reintroduce NTCP backlog pushback, with switch back to + previous tunnel when no longer backlogged + * Catch an nio exception in an NTCP logging statement if loglevel is WARN + * IRC Proxy: terminate all messages with \r\n (thanks TrivialPursuit!) + 2008-02-21 zzz * Raise inbound default bandwidth to 32KBps * Fix config.jsp that showed 0KBps share bandwidth by default diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 72bd13a50..13f8e487c 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -17,7 +17,7 @@ import net.i2p.CoreVersion; public class RouterVersion { public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $"; public final static String VERSION = "0.6.1.31"; - public final static long BUILD = 6; + public final static long BUILD = 7; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java index a3252fdaf..df95eb9b8 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java @@ -255,6 +255,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl { return false; } + // Right here is where we should use a persistent lease and caching like + // we do for outbound tunnel selection below??? + // randomize the ordering (so leases with equal # of failures per next // sort are randomly ordered) Collections.shuffle(leases); @@ -435,39 +438,79 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } } + /** + * Clean out old tunnels from a set. + * Caller must synchronize on tc. + */ + private void cleanTunnelCache(HashMap tc) { + List deleteList = new ArrayList(); + for (Iterator iter = tc.keySet().iterator(); iter.hasNext(); ) { + Destination dest = (Destination) iter.next(); + TunnelInfo tunnel = (TunnelInfo) tc.get(dest); + if (!getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) + deleteList.add(dest); + } + for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) { + Destination dest = (Destination) iter.next(); + tc.remove(dest); + } + } /** * Use the same outbound tunnel as we did for the same destination previously, * if possible, to keep the streaming lib happy + * Use two caches - although a cache of a list of tunnels per dest might be + * more elegant. + * Key the caches just on the dest, not on source+dest, as different sources + * simultaneously talking to the same dest is probably rare enough + * to not bother separating out. * */ private static HashMap _tunnelCache = new HashMap(); + private static HashMap _backloggedTunnelCache = new HashMap(); private static long _cleanTime = 0; private TunnelInfo selectOutboundTunnel(Destination to) { TunnelInfo tunnel; long now = getContext().clock().now(); synchronized (_tunnelCache) { if (now - _cleanTime > 5*60*1000) { // clean out periodically - List deleteList = new ArrayList(); - for (Iterator iter = _tunnelCache.keySet().iterator(); iter.hasNext(); ) { - Destination dest = (Destination) iter.next(); - tunnel = (TunnelInfo) _tunnelCache.get(dest); - if (!getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) - deleteList.add(dest); - } - for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) { - Destination dest = (Destination) iter.next(); - _tunnelCache.remove(dest); - } + cleanTunnelCache(_tunnelCache); + cleanTunnelCache(_backloggedTunnelCache); _cleanTime = now; } + /** + * If old tunnel is valid and no longer backlogged, use it. + * This prevents an active anonymity attack, where a peer could tell + * if you were the originator by backlogging the tunnel, then removing the + * backlog and seeing if traffic came back or not. + */ + tunnel = (TunnelInfo) _backloggedTunnelCache.get(to); + if (tunnel != null) { + if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) { + if (!getContext().commSystem().isBacklogged(tunnel.getPeer(1))) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Switching back to tunnel " + tunnel + " for dest " + to.calculateHash().toBase64()); + _backloggedTunnelCache.remove(to); + _tunnelCache.put(to, tunnel); + return tunnel; + } // else still backlogged + } else // no longer valid + _backloggedTunnelCache.remove(to); + } + // Use the same tunnel unless backlogged tunnel = (TunnelInfo) _tunnelCache.get(to); if (tunnel != null) { - if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) - return(tunnel); - else - _tunnelCache.remove(to); + if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) { + if (tunnel.getLength() <= 1 || !getContext().commSystem().isBacklogged(tunnel.getPeer(1))) + return tunnel; + // backlogged + if (_log.shouldLog(Log.WARN)) + _log.warn("Switching from backlogged " + tunnel + " for dest " + to.calculateHash().toBase64()); + _backloggedTunnelCache.put(to, tunnel); + } // else no longer valid + _tunnelCache.remove(to); } + // Pick a new tunnel tunnel = selectOutboundTunnel(); if (tunnel != null) _tunnelCache.put(to, tunnel); diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java index fe5569ef3..93a2e294a 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java @@ -325,10 +325,12 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { int writeBufs = 0; synchronized (_writeBufs) { writeBufs = _writeBufs.size(); } if (_log.shouldLog(Log.WARN)) - _log.warn("Too backlogged: queue time " + queueTime + " and the size is " + size + try { + _log.warn("Too backlogged: queue time " + queueTime + " and the size is " + size + ", wantsWrite? " + (0 != (_conKey.interestOps()&SelectionKey.OP_WRITE)) + ", currentOut set? " + currentOutboundSet + ", writeBufs: " + writeBufs + " on " + toString()); + } catch (Exception e) {} // java.nio.channels.CancelledKeyException _context.statManager().addRateData("ntcp.sendBacklogTime", queueTime, size); return true; //} else if (size > 32) { // another arbitrary limit.