From cf4d2b17c93535990a84ac00e866ea491cd4dce8 Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 23 Sep 2007 02:44:34 +0000 Subject: [PATCH] 2007-09-22 zzz * Send messages for the same destination out the same outbound tunnel to reduce out-of-order delivery. --- history.txt | 6 ++- .../src/net/i2p/router/RouterVersion.java | 4 +- .../net/i2p/router/TunnelManagerFacade.java | 4 ++ .../OutboundClientMessageOneShotJob.java | 42 ++++++++++++++++++- .../router/tunnel/pool/TunnelPoolManager.java | 15 ++++++- 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/history.txt b/history.txt index 933b95292c..2ebb05a575 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,8 @@ -$Id: history.txt,v 1.588 2007-09-18 14:09:21 zzz Exp $ +$Id: history.txt,v 1.589 2007-09-19 20:44:05 zzz Exp $ + +2007-09-22 zzz + * Send messages for the same destination out the same outbound + tunnel to reduce out-of-order delivery. 2007-09-19 zzz * i2psnark: Fix broken multifile torrent Delete; diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index bcd696f6c3..a68d3a5c3d 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.524 $ $Date: 2007-09-18 14:09:19 $"; + public final static String ID = "$Revision: 1.525 $ $Date: 2007-09-19 20:44:02 $"; public final static String VERSION = "0.6.1.29"; - 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/TunnelManagerFacade.java b/router/java/src/net/i2p/router/TunnelManagerFacade.java index ad4d1fad57..1caa56c9b8 100644 --- a/router/java/src/net/i2p/router/TunnelManagerFacade.java +++ b/router/java/src/net/i2p/router/TunnelManagerFacade.java @@ -41,6 +41,9 @@ public interface TunnelManagerFacade extends Service { * */ boolean isInUse(Hash peer); + + /** Is a tunnel a valid member of the pool? */ + public boolean isValidTunnel(Hash client, TunnelInfo tunnel); /** how many tunnels are we participating in? */ public int getParticipatingCount(); @@ -85,6 +88,7 @@ class DummyTunnelManagerFacade implements TunnelManagerFacade { public TunnelInfo selectOutboundTunnel() { return null; } public TunnelInfo selectOutboundTunnel(Hash destination) { return null; } public boolean isInUse(Hash peer) { return false; } + public boolean isValidTunnel(Hash client, TunnelInfo tunnel) { return false; } public int getParticipatingCount() { return 0; } public int getFreeTunnelCount() { return 0; } public int getOutboundTunnelCount() { return 0; } diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java index 34cbe41181..a3252fdaf6 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java @@ -2,6 +2,7 @@ package net.i2p.router.message; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -378,7 +379,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl { + _lease.getTunnelId() + " on " + _lease.getGateway().toBase64()); - _outTunnel = selectOutboundTunnel(); + _outTunnel = selectOutboundTunnel(_to); if (_outTunnel != null) { if (_log.shouldLog(Log.DEBUG)) _log.debug(getJobId() + ": Sending tunnel message out " + _outTunnel.getSendTunnelId(0) + " to " @@ -434,6 +435,45 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } } + + /** + * Use the same outbound tunnel as we did for the same destination previously, + * if possible, to keep the streaming lib happy + * + */ + private static HashMap _tunnelCache = 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); + } + _cleanTime = now; + } + tunnel = (TunnelInfo) _tunnelCache.get(to); + if (tunnel != null) { + if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) + return(tunnel); + else + _tunnelCache.remove(to); + } + tunnel = selectOutboundTunnel(); + if (tunnel != null) + _tunnelCache.put(to, tunnel); + } + return tunnel; + } /** * Pick an arbitrary outbound tunnel to send the message through, or null if * there aren't any around diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java index dcd9df5b78..e079be525f 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -187,6 +187,19 @@ public class TunnelPoolManager implements TunnelManagerFacade { return true; } + public boolean isValidTunnel(Hash client, TunnelInfo tunnel) { + if (tunnel.getExpiration() < _context.clock().now()) + return false; + TunnelPool pool; + if (tunnel.isInbound()) + pool = (TunnelPool)_clientInboundPools.get(client); + else + pool = (TunnelPool)_clientOutboundPools.get(client); + if (pool == null) + return false; + return pool.listTunnels().contains(tunnel); + } + public TunnelPoolSettings getInboundSettings() { return _inboundExploratory.getSettings(); } public TunnelPoolSettings getOutboundSettings() { return _outboundExploratory.getSettings(); } public void setInboundSettings(TunnelPoolSettings settings) { _inboundExploratory.setSettings(settings); } @@ -498,7 +511,7 @@ public class TunnelPoolManager implements TunnelManagerFacade { String cap = getCapacity(peer); TunnelId id = (info.isInbound() ? info.getReceiveTunnelId(j) : info.getSendTunnelId(j)); if (_context.routerHash().equals(peer)) - out.write("" + peer.toBase64().substring(0,4) + (id == null ? "" : ":" + id) + "" + cap + ""); + out.write("" + (id == null ? "" : "" + id) + ""); else out.write("" + peer.toBase64().substring(0,4) + (id == null ? "" : ":" + id) + cap + ""); }