diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java index 57edb5577..278971a7d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java @@ -37,6 +37,8 @@ class PeerCheckerTask extends TimerTask this.coordinator = coordinator; } + private Random random = new Random(); + public void run() { synchronized(coordinator.peers) @@ -105,13 +107,19 @@ class PeerCheckerTask extends TimerTask + " C: " + peer.isChoked(), Snark.DEBUG); + // Choke half of them rather than all so it isn't so drastic... + // unless this torrent is over the limit all by itself. + boolean overBWLimitChoke = upload > 0 && + ((overBWLimit && random.nextBoolean()) || + (coordinator.overUpBWLimit(uploaded))); + // If we are at our max uploaders and we have lots of other // interested peers try to make some room. // (Note use of coordinator.uploaders) if (((coordinator.uploaders == uploadLimit && coordinator.interestedAndChoking > 0) || coordinator.uploaders > uploadLimit - || overBWLimit) + || overBWLimitChoke) && !peer.isChoking()) { // Check if it still wants pieces from us. @@ -127,14 +135,18 @@ class PeerCheckerTask extends TimerTask it.remove(); removed.add(peer); } - else if (overBWLimit) + else if (overBWLimitChoke) { - Snark.debug("BW limit, choke peer: " + peer, + Snark.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer, Snark.INFO); peer.setChoking(true); uploaders--; coordinator.uploaders--; removedCount++; + + // Put it at the back of the list for fairness, even though we won't be unchoking this time + it.remove(); + removed.add(peer); } else if (peer.isInteresting() && peer.isChoked()) { @@ -220,7 +232,7 @@ class PeerCheckerTask extends TimerTask } // Optimistically unchoke a peer - if (!overBWLimit) + if ((!overBWLimit) && !coordinator.overUpBWLimit(uploaded)) coordinator.unchokePeer(); // Put peers back at the end of the list that we removed earlier. diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java index 14527bd32..275a05c35 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java @@ -392,6 +392,23 @@ class PeerConnectionOut implements Runnable req.sendTime = System.currentTimeMillis(); } + // Used by PeerState to limit pipelined requests + int queuedBytes() + { + int total = 0; + synchronized(sendQueue) + { + Iterator it = sendQueue.iterator(); + while (it.hasNext()) + { + Message m = (Message)it.next(); + if (m.type == Message.PIECE) + total += m.length; + } + } + return total; + } + void sendPiece(int piece, int begin, int length, byte[] bytes) { Message m = new Message(); diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 8efd2332b..2304f050b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -38,8 +38,8 @@ public class PeerCoordinator implements PeerListener // package local for access by CheckDownLoadersTask final static long CHECK_PERIOD = 40*1000; // 40 seconds - final static int MAX_CONNECTIONS = 24; - final static int MAX_UPLOADERS = 4; + final static int MAX_CONNECTIONS = 16; + final static int MAX_UPLOADERS = 6; // Approximation of the number of current uploaders. // Resynced by PeerChecker once in a while. @@ -286,6 +286,14 @@ public class PeerCoordinator implements PeerListener // toDisconnect = peer to get out of synchronized(peers) peer.disconnect(false); // Don't deregister this connection/peer. } + // This is already checked in addPeer() but we could have gone over the limit since then + else if (peers.size() >= MAX_CONNECTIONS) + { + if (_log.shouldLog(Log.WARN)) + _log.warn("Already at MAX_CONNECTIONS in connected() with peer: " + peer); + // toDisconnect = peer to get out of synchronized(peers) + peer.disconnect(false); + } else { if (_log.shouldLog(Log.INFO)) @@ -307,6 +315,7 @@ public class PeerCoordinator implements PeerListener } } + // caller must synchronize on peers private static Peer peerIDInList(PeerID pid, List peers) { Iterator it = peers.iterator(); @@ -328,9 +337,13 @@ public class PeerCoordinator implements PeerListener } boolean need_more; + int peersize = 0; synchronized(peers) { - need_more = !peer.isConnected() && peers.size() < MAX_CONNECTIONS; + peersize = peers.size(); + // This isn't a strict limit, as we may have several pending connections; + // thus there is an additional check in connected() + need_more = (!peer.isConnected()) && peersize < MAX_CONNECTIONS; // Check if we already have this peer before we build the connection Peer old = peerIDInList(peer.getPeerID(), peers); need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000)); @@ -354,15 +367,14 @@ public class PeerCoordinator implements PeerListener new I2PThread(r, threadName).start(); return true; } - else - if (_log.shouldLog(Log.DEBUG)) { - if (peer.isConnected()) - _log.info("Add peer already connected: " + peer); - else - _log.info("MAX_CONNECTIONS = " + MAX_CONNECTIONS - + " not accepting extra peer: " + peer); - } - return false; + if (_log.shouldLog(Log.DEBUG)) { + if (peer.isConnected()) + _log.info("Add peer already connected: " + peer); + else + _log.info("Connections: " + peersize + "/" + MAX_CONNECTIONS + + " not accepting extra peer: " + peer); + } + return false; } @@ -842,5 +854,10 @@ public class PeerCoordinator implements PeerListener { return Snark.overUpBWLimit(); } + + public boolean overUpBWLimit(long total) + { + return Snark.overUpBWLimit(total * 1000 / CHECK_PERIOD); + } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index dd38ac357..8f8b7bbc6 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -62,7 +62,8 @@ class PeerState // If we have te resend outstanding requests (true after we got choked). private boolean resend = false; - private final static int MAX_PIPELINE = 2; + private final static int MAX_PIPELINE = 2; // this is for outbound requests + private final static int MAX_PIPELINE_BYTES = 128*1024; // this is for inbound requests private final static int PARTSIZE = 32*1024; // Snark was 16K, i2p-bt uses 64KB private final static int MAX_PARTSIZE = 64*1024; // Don't let anybody request more than this @@ -185,6 +186,15 @@ class PeerState return; } + // Limit total pipelined requests to MAX_PIPELINE bytes + // to conserve memory and prevent DOS + if (out.queuedBytes() + length > MAX_PIPELINE_BYTES) + { + if (_log.shouldLog(Log.WARN)) + _log.warn("Discarding request over pipeline limit from " + peer); + return; + } + byte[] pieceBytes = listener.gotRequest(peer, piece, begin, length); if (pieceBytes == null) { diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index f0fd66eaf..f7ea7f0fa 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -791,4 +791,9 @@ public class Snark Snark.debug("Total up bw: " + total + " Limit: " + limit, Snark.WARNING); return total > limit; } + + public static boolean overUpBWLimit(long total) { + long limit = 1024l * I2PSnarkUtil.instance().getMaxUpBW(); + return total > limit; + } } diff --git a/apps/routerconsole/jsp/help.jsp b/apps/routerconsole/jsp/help.jsp index 41103adaf..b1319ffd7 100644 --- a/apps/routerconsole/jsp/help.jsp +++ b/apps/routerconsole/jsp/help.jsp @@ -11,7 +11,10 @@ <%@include file="summary.jsp" %>
-hmm. we should probably have some help text here.
+

Help

+Sorry, there's no help text here yet, so check out the +FAQ on www.i2p2.i2p. +

Legal stuff

The I2P router (router.jar) and SDK (i2p.jar) are almost entirely public domain, with diff --git a/history.txt b/history.txt index cc2a58765..ed2c146d7 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,22 @@ +2008-05-18 zzz + * Throttle: Reject tunnels for first 20m uptime (was 10m) + * TunnelPeerSelectors: + - Re-enable strict ordering of peers, + based on XOR distance from a random hash + - Restrict peers with uptime < 90m from tunnels (was 2h), + which is really 60m due to rounding in netDb publishing. + * i2psnark: + - Limit max pipelined requests from a single peer to 128KB + (was unlimited; i2p-bt default is 5 * 64KB) + - Increase max uploaders per torrent to 6 (was 4) + - Reduce max connections per torrent to 16 (was 24) to increase + unchoke time and reduce memory consumption + - Strictly enforce max connections per torrent + - Choke more gradually when over BW limit + * help.jsp: Add a link to the FAQ + * peers.jsp: Fix UDP direction indicators + * hosts.txt: Add update.postman.i2p + 2008-05-12 zzz * Outbound message: - Tweak the cache key for efficiency diff --git a/hosts.txt b/hosts.txt index 77b1ce87a..72951bd11 100644 --- a/hosts.txt +++ b/hosts.txt @@ -306,3 +306,4 @@ perv.i2p=HazSt3kSqVjpMO9Ol9HPjXCfzTLurOPjSeN47UxMLLs4lm5SJJHP-p3vA4sTfxrR3z7Cqq5 false.i2p=V5EeX1UrVanCQhE9q-Nj5UFRyQiH6b~lSO7qe8hgxGZkymrpHFZ5j5D9rVOjsogokon1bZF5NPlPdzI~d4Ap7UyqBR~90vhFxsIKednRZLdf46JgjYTZq~ct-Bi3sdpBXdg04L8i4dStE4jkdvl6NF96MfQKdt6mtYFeaXb0XhPx~04NECG5~y~mTYcMjcvrftt5uulLbT6TcGmJ0KV5Xu2UVnkN3zOaQEObIIDZT4wkz9jOqaiJzMHNJqWc4GU4ocIfwxeMkSn9qvA0Q1AXuM~z11~wgHYLVEFoN5k0O4aB8b1r1WtpZTojZ9ADThW89q~AcD981nIYnRp59cmyqBdN7X-71cBrKC7QfnCRJpbwoVrn7kePw1dCu6Bobnd4~a74abxjFeCxVzQxSTbkey6f~wJXE2JPAqfsM1EKXsdqUZQJOP0ngQu16srSpqMSxkqHzlr3US~Vn9EgMcHuDCkdctwo7stwn0UQ34sSF9sLhtmlHIGqatDhfmYEGmSiAAAA mtn.i2p2.i2p=G6VmsrLYbdcxBq585OUcQn7wbwC7J5jfXDWWL6lPBw5iq68VxqxibraiPwwF6NM2aHV8BkqyCKYSL9fUuYWoeUc1zL~2l1DX2x~LfyItGJKDIUGImWQivXF1w7EGYMhjq4UCmPKTsnl4G86oKW8PGaaF8mzjjUKW1R7G7941my~mnbeTrhjlLgaMK-tauVodgTPIYkxfMJaq3zWuirztuUgDcXXIbkpzaA2Iben0VqbjbMJisj4fFh0EvqNkYAG54YBc26~W6SPWyBgZilXvFlcizF90Q5NkIGMMHXTq46qEYHkpQC3CoaH6PMNVDetDPmFc3QXmc68cNcj~VPh4XVsn3qiKhXuRdXggEC3RoTcxqaeassfIG5xhRdnJzGSVhYUE3At~8wI-AuRV~AglV1Q-AZTWT~9VxBzcxfI1PpfzeA-5z5T4542bh1e-RM9tzXEx5ErPCt6M~zJ2~4-tz-aBsZEhBkn0iDi8pazshg6lTl1~hCnueZBxYICqPrlBAAAA i2jump.i2p=DGLCAiwuqO7vGljO8ya-yoQ~ldk~MCUCjxSL2RLIOQxHAZkgFprOLsoqgMJNmjL0cE2aFeNxUfLTkg5yQ10P7EBtiaL-PJj4YSe4YWzymM0RtWOCCJtpf1168x80b5AHj2tTHELoyPr3UNa1WEg0T~st0SN6Bpo227TAPTw-xVwx3apIvpBUi-LubQrVWO0geHgeQReCzceFSuATzyBLK6m7Ki4ezCIJX97b0wwZcMqSgkH1Zvf7gzA55ZQA24aUl2jMc69DLSAtEDI9lkaEgLAwgZ0I6NK08fu9GTkMemJJIKdh4mrT3FLVXyF6fxKWXhs6il8ju43kVnFPfmM7~XAsU1VP7pwjHNS2h3wO1RoaeXUJmGcByG1aP-DcJfvNk-n5AteOynCFQ~w39VsCuN8Fq8Q7AWPNLm2NfiitJzKJvIaYJuVVZLxxskTcrwMSb3IEvonYtCYL2bo84eLZGQoFWDeKw3krClP8u1U5R00Tgty7t5ixJ1JT4yiY90oGAAAA +update.postman.i2p=HAEa~0ScLNyqgXYiv-~2OpEx8tv~pickuOTLrflg0vumyON67YFHTZXI4ET4mvU0ZMGPghJUbWBIrVGrJSltoRRjGxcuZ84ynSrs4wMPDWqlN6Jqln7xMBTn~pTSYc09uCrrBRcrbfiK9179YaMKMIYCjOUxlwfdEzzIxhJ8Gu-zbU6bNlCEMjLwZqZ5lYliypR05l7HthJl7LL-~PXZGHO9uyMgOIPKxQgcW6L2U7Tk7vj4CNbP-gVuHkorz0H9oQ3i8qRLvFvdVBKygVYBU6TWGAlQgzccwhOUTKTcJfSJ2nqzEh48qXXPDgI~4IweE8q9wecT6Wn-UmoX51txNQ6LJVvpGS2IOwXC2P4og22Xja5wxH~0GQ5JTiBP4AjArGbY3klKS0h7Jf5-J9d1DSIL2EZVN33NAMit-iJK8Siw6SIRyBzDXxaIcWy4bggrrRIA7ce7y8ahyM~y7UvrwjFOlVnDa3Lvs35kU87Q-HklFJuyPTA756s4qoD7bf0pAAAA diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index 21ecf412a..8035d89fa 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -90,7 +90,7 @@ class RouterThrottleImpl implements RouterThrottle { return TunnelHistory.TUNNEL_REJECT_CRIT; } - if (_context.router().getUptime() < 10*60*1000) + if (_context.router().getUptime() < 20*60*1000) return TunnelHistory.TUNNEL_REJECT_CRIT; long lag = _context.jobQueue().getMaxLag(); diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 045d01e8c..7099c1f5d 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.33"; - public final static long BUILD = 5; + public final static long BUILD = 6; 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/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 967ce0458..61eb3a8fb 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1682,9 +1682,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority */ buf.append(" "); if (peer.isInbound()) - buf.append("> "); - else buf.append("< "); + else + buf.append("> "); if (peer.getWeRelayToThemAs() > 0) buf.append("^"); else diff --git a/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java index e851a68f0..a5c905f47 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java @@ -29,10 +29,7 @@ class ClientPeerSelector extends TunnelPeerSelector { matches.remove(ctx.routerHash()); ArrayList rv = new ArrayList(matches); if (rv.size() > 1) -/*** removed until we fix SSU reachability orderPeers(rv, settings.getRandomKey()); -***/ - Collections.shuffle(rv, ctx.random()); if (settings.isInbound()) rv.add(0, ctx.routerHash()); else diff --git a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java index 815f06443..4ce344ea4 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java @@ -50,10 +50,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { matches.remove(ctx.routerHash()); ArrayList rv = new ArrayList(matches); if (rv.size() > 1) -/*** removed until we fix SSU reachability orderPeers(rv, settings.getRandomKey()); -***/ - Collections.shuffle(rv, ctx.random()); if (settings.isInbound()) rv.add(0, ctx.routerHash()); else diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index 1a553fec7..b2012e1ad 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -372,8 +372,9 @@ public abstract class TunnelPeerSelector { return true; } } else { - if ( (infoAge + uptimeMs < 2*60*60*1000) && (ctx.router().getUptime() > DONT_EXCLUDE_PERIOD) ) { - // up for less than 2 hours, so exclude it + if ( (infoAge + uptimeMs < 90*60*1000) && (ctx.router().getUptime() > DONT_EXCLUDE_PERIOD) ) { + // up for less than 90 min (which is really 1h since an uptime of 1h-2h is published as 90m), + // so exclude it return true; } else { return false;