* 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!)
This commit is contained in:
@ -164,7 +164,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
|||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("inbound: "+outmsg);
|
_log.info("inbound: "+outmsg);
|
||||||
}
|
}
|
||||||
outmsg=outmsg+"\n";
|
outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3
|
||||||
output.write(outmsg.getBytes("ISO-8859-1"));
|
output.write(outmsg.getBytes("ISO-8859-1"));
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
@ -238,7 +238,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
|||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("outbound: "+outmsg);
|
_log.info("outbound: "+outmsg);
|
||||||
}
|
}
|
||||||
outmsg=outmsg+"\n";
|
outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3
|
||||||
output.write(outmsg.getBytes("ISO-8859-1"));
|
output.write(outmsg.getBytes("ISO-8859-1"));
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
@ -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
|
2008-02-21 zzz
|
||||||
* Raise inbound default bandwidth to 32KBps
|
* Raise inbound default bandwidth to 32KBps
|
||||||
* Fix config.jsp that showed 0KBps share bandwidth by default
|
* Fix config.jsp that showed 0KBps share bandwidth by default
|
||||||
|
@ -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.31";
|
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[]) {
|
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);
|
||||||
|
@ -255,6 +255,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
return false;
|
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
|
// randomize the ordering (so leases with equal # of failures per next
|
||||||
// sort are randomly ordered)
|
// sort are randomly ordered)
|
||||||
Collections.shuffle(leases);
|
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,
|
* Use the same outbound tunnel as we did for the same destination previously,
|
||||||
* if possible, to keep the streaming lib happy
|
* 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 _tunnelCache = new HashMap();
|
||||||
|
private static HashMap _backloggedTunnelCache = new HashMap();
|
||||||
private static long _cleanTime = 0;
|
private static long _cleanTime = 0;
|
||||||
private TunnelInfo selectOutboundTunnel(Destination to) {
|
private TunnelInfo selectOutboundTunnel(Destination to) {
|
||||||
TunnelInfo tunnel;
|
TunnelInfo tunnel;
|
||||||
long now = getContext().clock().now();
|
long now = getContext().clock().now();
|
||||||
synchronized (_tunnelCache) {
|
synchronized (_tunnelCache) {
|
||||||
if (now - _cleanTime > 5*60*1000) { // clean out periodically
|
if (now - _cleanTime > 5*60*1000) { // clean out periodically
|
||||||
List deleteList = new ArrayList();
|
cleanTunnelCache(_tunnelCache);
|
||||||
for (Iterator iter = _tunnelCache.keySet().iterator(); iter.hasNext(); ) {
|
cleanTunnelCache(_backloggedTunnelCache);
|
||||||
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;
|
_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);
|
tunnel = (TunnelInfo) _tunnelCache.get(to);
|
||||||
if (tunnel != null) {
|
if (tunnel != null) {
|
||||||
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel))
|
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
|
||||||
return(tunnel);
|
if (tunnel.getLength() <= 1 || !getContext().commSystem().isBacklogged(tunnel.getPeer(1)))
|
||||||
else
|
return tunnel;
|
||||||
_tunnelCache.remove(to);
|
// 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();
|
tunnel = selectOutboundTunnel();
|
||||||
if (tunnel != null)
|
if (tunnel != null)
|
||||||
_tunnelCache.put(to, tunnel);
|
_tunnelCache.put(to, tunnel);
|
||||||
|
@ -325,10 +325,12 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
|||||||
int writeBufs = 0;
|
int writeBufs = 0;
|
||||||
synchronized (_writeBufs) { writeBufs = _writeBufs.size(); }
|
synchronized (_writeBufs) { writeBufs = _writeBufs.size(); }
|
||||||
if (_log.shouldLog(Log.WARN))
|
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))
|
+ ", wantsWrite? " + (0 != (_conKey.interestOps()&SelectionKey.OP_WRITE))
|
||||||
+ ", currentOut set? " + currentOutboundSet
|
+ ", currentOut set? " + currentOutboundSet
|
||||||
+ ", writeBufs: " + writeBufs + " on " + toString());
|
+ ", writeBufs: " + writeBufs + " on " + toString());
|
||||||
|
} catch (Exception e) {} // java.nio.channels.CancelledKeyException
|
||||||
_context.statManager().addRateData("ntcp.sendBacklogTime", queueTime, size);
|
_context.statManager().addRateData("ntcp.sendBacklogTime", queueTime, size);
|
||||||
return true;
|
return true;
|
||||||
//} else if (size > 32) { // another arbitrary limit.
|
//} else if (size > 32) { // another arbitrary limit.
|
||||||
|
Reference in New Issue
Block a user