From 8cba2f4236e7b78829636cf34ca8f597ab567d35 Mon Sep 17 00:00:00 2001 From: jrandom <jrandom> Date: Wed, 19 Apr 2006 17:46:51 +0000 Subject: [PATCH] 2006-04-19 jrandom * Adjust how we pick high capacity peers to allow the inclusion of fast peers (the previous filter assumed an old usage pattern) * New set of stats to help track per-packet-type bandwidth usage better * Cut out the proactive tail drop from the SSU transport, for now * Reduce the frequency of tunnel build attempts while we're saturated * Don't drop tunnel requests as easily - prefer to explicitly reject them --- .../src/net/i2p/router/web/GraphHelper.java | 16 +++- .../net/i2p/router/web/SummaryListener.java | 2 +- core/java/src/net/i2p/stat/Rate.java | 1 + history.txt | 10 ++- .../net/i2p/data/i2np/I2NPMessageImpl.java | 2 +- .../src/net/i2p/router/LoadTestManager.java | 6 +- router/java/src/net/i2p/router/Router.java | 78 +++++++++++++++++++ .../net/i2p/router/RouterThrottleImpl.java | 55 +------------ .../src/net/i2p/router/RouterVersion.java | 4 +- .../router/peermanager/ProfileOrganizer.java | 4 + .../router/transport/udp/PacketBuilder.java | 12 +++ .../router/transport/udp/PacketHandler.java | 26 +++++++ .../i2p/router/transport/udp/PeerState.java | 2 +- .../i2p/router/transport/udp/UDPSender.java | 16 +++- .../router/transport/udp/UDPTransport.java | 2 + .../i2p/router/tunnel/pool/BuildExecutor.java | 36 ++++++++- .../i2p/router/tunnel/pool/BuildHandler.java | 12 +-- 17 files changed, 212 insertions(+), 72 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java index 3260a2119d..6d247e712d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -62,8 +62,10 @@ public class GraphHelper { + "\" title=\"Combined bandwidth graph\" />\n"); List listeners = StatSummarizer.instance().getListeners(); - for (int i = 0; i < listeners.size(); i++) { - SummaryListener lsnr = (SummaryListener)listeners.get(i); + TreeSet ordered = new TreeSet(new AlphaComparator()); + ordered.addAll(listeners); + for (Iterator iter = ordered.iterator(); iter.hasNext(); ) { + SummaryListener lsnr = (SummaryListener)iter.next(); Rate r = lsnr.getRate(); String title = r.getRateStat().getName() + " for " + DataHelper.formatDuration(_periodCount * r.getPeriod()); _out.write("<img src=\"viewstat.jsp?stat=" + r.getRateStat().getName() @@ -108,3 +110,13 @@ public class GraphHelper { return ""; } } + +class AlphaComparator implements Comparator { + public int compare(Object lhs, Object rhs) { + SummaryListener l = (SummaryListener)lhs; + SummaryListener r = (SummaryListener)rhs; + String lName = l.getRate().getRateStat().getName() + "." + l.getRate().getPeriod(); + String rName = r.getRate().getRateStat().getName() + "." + r.getRate().getPeriod(); + return lName.compareTo(rName); + } +} \ No newline at end of file diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index 546968ea33..30370a60a6 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -153,7 +153,7 @@ class SummaryRenderer { * specify who can get it from where, etc. * */ - public static void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { + public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { long end = ctx.clock().now(); long start = end - 60*1000*SummaryListener.PERIODS; long begin = System.currentTimeMillis(); diff --git a/core/java/src/net/i2p/stat/Rate.java b/core/java/src/net/i2p/stat/Rate.java index b043e97723..8ac385feb6 100644 --- a/core/java/src/net/i2p/stat/Rate.java +++ b/core/java/src/net/i2p/stat/Rate.java @@ -433,6 +433,7 @@ public class Rate { public boolean equals(Object obj) { if ((obj == null) || (obj.getClass() != Rate.class)) return false; + if (obj == this) return true; Rate r = (Rate) obj; return _period == r.getPeriod() && _creationDate == r.getCreationDate() && //_lastCoalesceDate == r.getLastCoalesceDate() && diff --git a/history.txt b/history.txt index aba625098c..4e9b8d763e 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,12 @@ -$Id: history.txt,v 1.459 2006/04/15 02:15:19 jrandom Exp $ +$Id: history.txt,v 1.460 2006/04/15 02:58:12 jrandom Exp $ + +2006-04-19 jrandom + * Adjust how we pick high capacity peers to allow the inclusion of fast + peers (the previous filter assumed an old usage pattern) + * New set of stats to help track per-packet-type bandwidth usage better + * Cut out the proactive tail drop from the SSU transport, for now + * Reduce the frequency of tunnel build attempts while we're saturated + * Don't drop tunnel requests as easily - prefer to explicitly reject them * 2006-04-15 0.6.1.16 released diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 0e34438f19..ba57d3e093 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -333,7 +333,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM } protected void verifyUnwritten() { - if (_written) throw new RuntimeException("Already written"); + if (_written) throw new IllegalStateException("Already written"); } protected void written() { _written = true; } protected void read() { _read = true; } diff --git a/router/java/src/net/i2p/router/LoadTestManager.java b/router/java/src/net/i2p/router/LoadTestManager.java index 25c90007c4..4dac0cf6ef 100644 --- a/router/java/src/net/i2p/router/LoadTestManager.java +++ b/router/java/src/net/i2p/router/LoadTestManager.java @@ -506,9 +506,9 @@ public class LoadTestManager { } private int getBps() { - int used1s = RouterThrottleImpl.get1sRate(_context); - int used1m = RouterThrottleImpl.get1mRate(_context); - int used5m = RouterThrottleImpl.get5mRate(_context); + int used1s = _context.router().get1sRate(); + int used1m = _context.router().get1mRate(); + int used5m = _context.router().get5mRate(); return Math.max(used1s, Math.max(used1m, used5m)); } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 2f4bb8328f..f851e8a929 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -35,8 +35,10 @@ import net.i2p.router.message.GarlicMessageHandler; //import net.i2p.router.message.TunnelMessageHandler; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.startup.StartupJob; +import net.i2p.router.transport.FIFOBandwidthLimiter; import net.i2p.stat.Rate; import net.i2p.stat.RateStat; +import net.i2p.stat.StatManager; import net.i2p.util.FileUtil; import net.i2p.util.I2PThread; import net.i2p.util.SimpleTimer; @@ -1029,6 +1031,82 @@ public class Router { t.start(); return true; } + + private static final String PROP_BANDWIDTH_SHARE_PERCENTAGE = "router.sharePercentage"; + + /** + * What fraction of the bandwidth specified in our bandwidth limits should + * we allow to be consumed by participating tunnels? + * + */ + public double getSharePercentage() { + RouterContext ctx = _context; + if (ctx == null) return 0; + String pct = ctx.getProperty(PROP_BANDWIDTH_SHARE_PERCENTAGE); + if (pct != null) { + try { + double d = Double.parseDouble(pct); + if (d > 1) + return d/100d; // *cough* sometimes its 80 instead of .8 (!stab jrandom) + else + return d; + } catch (NumberFormatException nfe) { + if (_log.shouldLog(Log.INFO)) + _log.info("Unable to get the share percentage"); + } + } + return 0.8; + } + + public int get1sRate() { return get1sRate(false); } + public int get1sRate(boolean outboundOnly) { + RouterContext ctx = _context; + if (ctx != null) { + FIFOBandwidthLimiter bw = ctx.bandwidthLimiter(); + if (bw != null) { + int out = (int)bw.getSendBps(); + if (outboundOnly) + return out; + return (int)Math.max(out, bw.getReceiveBps()); + } + } + return 0; + } + public int get1mRate() { return get1mRate(false); } + public int get1mRate(boolean outboundOnly) { + int send = 0; + RouterContext ctx = _context; + if (ctx == null) + return 0; + StatManager mgr = ctx.statManager(); + if (mgr == null) + return 0; + RateStat rs = mgr.getRate("bw.sendRate"); + if (rs != null) + send = (int)rs.getRate(1*60*1000).getAverageValue(); + if (outboundOnly) + return send; + int recv = 0; + rs = mgr.getRate("bw.recvRate"); + if (rs != null) + recv = (int)rs.getRate(1*60*1000).getAverageValue(); + return Math.max(send, recv); + } + public int get5mRate() { return get5mRate(false); } + public int get5mRate(boolean outboundOnly) { + int send = 0; + RateStat rs = _context.statManager().getRate("bw.sendRate"); + if (rs != null) + send = (int)rs.getRate(5*60*1000).getAverageValue(); + if (outboundOnly) + return send; + int recv = 0; + rs = _context.statManager().getRate("bw.recvRate"); + if (rs != null) + recv = (int)rs.getRate(5*60*1000).getAverageValue(); + return Math.max(send, recv); + } + } /** diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index 0b54415ea6..05c2582a59 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -32,8 +32,7 @@ class RouterThrottleImpl implements RouterThrottle { private static final String PROP_MAX_TUNNELS = "router.maxParticipatingTunnels"; private static final String PROP_DEFAULT_KBPS_THROTTLE = "router.defaultKBpsThrottle"; - private static final String PROP_BANDWIDTH_SHARE_PERCENTAGE = "router.sharePercentage"; - + /** tunnel acceptance */ public static final int TUNNEL_ACCEPT = 0; @@ -218,32 +217,6 @@ class RouterThrottleImpl implements RouterThrottle { return TUNNEL_ACCEPT; } - static int get1sRate(RouterContext ctx) { - return (int)Math.max(ctx.bandwidthLimiter().getSendBps(), ctx.bandwidthLimiter().getReceiveBps()); - } - static int get1mRate(RouterContext ctx) { - int send = 0; - RateStat rs = ctx.statManager().getRate("bw.sendRate"); - if (rs != null) - send = (int)rs.getRate(1*60*1000).getAverageValue(); - int recv = 0; - rs = ctx.statManager().getRate("bw.recvRate"); - if (rs != null) - recv = (int)rs.getRate(1*60*1000).getAverageValue(); - return Math.max(send, recv); - } - static int get5mRate(RouterContext ctx) { - int send = 0; - RateStat rs = ctx.statManager().getRate("bw.sendRate"); - if (rs != null) - send = (int)rs.getRate(5*60*1000).getAverageValue(); - int recv = 0; - rs = ctx.statManager().getRate("bw.recvRate"); - if (rs != null) - recv = (int)rs.getRate(5*60*1000).getAverageValue(); - return Math.max(send, recv); - } - private static final int DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE = 60; // .1KBps private static final int MIN_AVAILABLE_BPS = 4*1024; // always leave at least 4KBps free when allowing @@ -256,10 +229,10 @@ class RouterThrottleImpl implements RouterThrottle { private boolean allowTunnel(double bytesAllocated, int numTunnels) { int maxKBps = Math.min(_context.bandwidthLimiter().getOutboundKBytesPerSecond(), _context.bandwidthLimiter().getInboundKBytesPerSecond()); int used1s = 0; //get1sRate(_context); // dont throttle on the 1s rate, its too volatile - int used1m = get1mRate(_context); + int used1m = _context.router().get1mRate(); int used5m = 0; //get5mRate(_context); // don't throttle on the 5m rate, as that'd hide available bandwidth int used = Math.max(Math.max(used1s, used1m), used5m); - double share = getSharePercentage(); + double share = _context.router().getSharePercentage(); int availBps = (int)(((maxKBps*1024)*share) - used); //(int)(((maxKBps*1024) - used) * getSharePercentage()); _context.statManager().addRateData("router.throttleTunnelBytesUsed", used, maxKBps); @@ -326,28 +299,6 @@ class RouterThrottleImpl implements RouterThrottle { } } - /** - * What fraction of the bandwidth specified in our bandwidth limits should - * we allow to be consumed by participating tunnels? - * - */ - private double getSharePercentage() { - String pct = _context.getProperty(PROP_BANDWIDTH_SHARE_PERCENTAGE); - if (pct != null) { - try { - double d = Double.parseDouble(pct); - if (d > 1) - return d/100d; // *cough* sometimes its 80 instead of .8 (!stab jrandom) - else - return d; - } catch (NumberFormatException nfe) { - if (_log.shouldLog(Log.INFO)) - _log.info("Unable to get the share percentage"); - } - } - return 0.8; - } - /** dont ever probabalistically throttle tunnels if we have less than this many */ private int getMinThrottleTunnels() { try { diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 4cacb71182..552461e9a6 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.399 $ $Date: 2006/04/15 02:15:23 $"; + public final static String ID = "$Revision: 1.400 $ $Date: 2006/04/15 02:58:14 $"; public final static String VERSION = "0.6.1.16"; - public final static long BUILD = 0; + public final static long BUILD = 1; 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/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index b8ea42c2aa..3b80749e11 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -251,10 +251,12 @@ public class ProfileOrganizer { // we only use selectHighCapacityPeers when we are selecting for PURPOSE_TEST // or we are falling back due to _fastPeers being too small, so we can always // exclude the fast peers + /* if (exclude == null) exclude = new HashSet(_fastPeers.keySet()); else exclude.addAll(_fastPeers.keySet()); + */ locked_selectPeers(_highCapacityPeers, howMany, exclude, matches); } if (matches.size() < howMany) { @@ -809,6 +811,8 @@ public class ProfileOrganizer { } else { if (_log.shouldLog(Log.INFO)) _log.info("Peer " + peer.toBase64() + " is locally known, allowing its use"); + // perhaps check to see if they are active? + return true; } } else { diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 86ced1b649..9fad971634 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -402,6 +402,7 @@ public class PacketBuilder { authenticate(packet, ourIntroKey, ourIntroKey, iv); setTo(packet, to, state.getSentPort()); _ivCache.release(iv); + packet.setMessageType(53); return packet; } @@ -465,6 +466,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, state.getIntroKey(), state.getIntroKey()); setTo(packet, to, state.getSentPort()); + packet.setMessageType(52); return packet; } @@ -571,6 +573,7 @@ public class PacketBuilder { } setTo(packet, to, state.getSentPort()); + packet.setMessageType(51); return packet; } @@ -623,6 +626,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, toCipherKey, toMACKey); setTo(packet, toIP, toPort); + packet.setMessageType(50); return packet; } @@ -667,6 +671,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, aliceIntroKey, aliceIntroKey); setTo(packet, aliceIP, alicePort); + packet.setMessageType(49); return packet; } @@ -713,6 +718,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, charlieCipherKey, charlieMACKey); setTo(packet, charlieIP, charliePort); + packet.setMessageType(48); return packet; } @@ -757,6 +763,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, bobCipherKey, bobMACKey); setTo(packet, bobIP, bobPort); + packet.setMessageType(47); return packet; } @@ -854,6 +861,7 @@ public class PacketBuilder { if (encrypt) authenticate(packet, new SessionKey(introKey), new SessionKey(introKey)); setTo(packet, introHost, introPort); + packet.setMessageType(46); return packet; } @@ -903,6 +911,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, charlie.getCurrentCipherKey(), charlie.getCurrentMACKey()); setTo(packet, charlie.getRemoteIPAddress(), charlie.getRemotePort()); + packet.setMessageType(45); return packet; } @@ -963,6 +972,7 @@ public class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, aliceIntroKey, aliceIntroKey); setTo(packet, aliceAddr, alice.getPort()); + packet.setMessageType(44); return packet; } @@ -994,6 +1004,8 @@ public class PacketBuilder { // its just for hole punching packet.getPacket().setLength(0); setTo(packet, to, port); + + packet.setMessageType(43); return packet; } diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java index 882054f1b6..af9ef971f7 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java @@ -68,6 +68,17 @@ public class PacketHandler { _context.statManager().createRateStat("udp.packetVerifyTimeSlow", "How long it takes the PacketHandler to verify a data packet after dequeueing when its slow (period is dequeue time)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); _context.statManager().createRateStat("udp.packetValidateMultipleCount", "How many times we validate a packet, if done more than once (period = afterValidate-enqueue)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); _context.statManager().createRateStat("udp.packetNoValidationLifetime", "How long packets that are never validated are around for", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.sessionRequest", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.sessionConfirmed", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.sessionCreated", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.dataKnown", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.dataKnownAck", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.dataUnknown", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.dataUnknownAck", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.test", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.relayRequest", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.relayIntro", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); + _context.statManager().createRateStat("udp.receivePacketSize.relayResponse", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", new long[] { 60*1000, 10*60*1000 }); } public void startup() { @@ -440,14 +451,17 @@ public class PacketHandler { case UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST: _state = 47; _establisher.receiveSessionRequest(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.sessionRequest", packet.getPacket().getLength(), packet.getLifetime()); break; case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED: _state = 48; _establisher.receiveSessionConfirmed(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.sessionConfirmed", packet.getPacket().getLength(), packet.getLifetime()); break; case UDPPacket.PAYLOAD_TYPE_SESSION_CREATED: _state = 49; _establisher.receiveSessionCreated(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.sessionCreated", packet.getPacket().getLength(), packet.getLifetime()); break; case UDPPacket.PAYLOAD_TYPE_DATA: _state = 50; @@ -472,6 +486,14 @@ public class PacketHandler { } packet.beforeReceiveFragments(); _inbound.receiveData(state, dr); + _context.statManager().addRateData("udp.receivePacketSize.dataKnown", packet.getPacket().getLength(), packet.getLifetime()); + if (dr.readFragmentCount() <= 0) + _context.statManager().addRateData("udp.receivePacketSize.dataKnownAck", packet.getPacket().getLength(), packet.getLifetime()); + } else { + _context.statManager().addRateData("udp.receivePacketSize.dataUnknown", packet.getPacket().getLength(), packet.getLifetime()); + UDPPacketReader.DataReader dr = reader.getDataReader(); + if (dr.readFragmentCount() <= 0) + _context.statManager().addRateData("udp.receivePacketSize.dataUnknownAck", packet.getPacket().getLength(), packet.getLifetime()); } break; case UDPPacket.PAYLOAD_TYPE_TEST: @@ -479,21 +501,25 @@ public class PacketHandler { if (_log.shouldLog(Log.DEBUG)) _log.debug("Received test packet: " + reader + " from " + from); _testManager.receiveTest(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.test", packet.getPacket().getLength(), packet.getLifetime()); break; case UDPPacket.PAYLOAD_TYPE_RELAY_REQUEST: if (_log.shouldLog(Log.INFO)) _log.info("Received relay request packet: " + reader + " from " + from); _introManager.receiveRelayRequest(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.relayRequest", packet.getPacket().getLength(), packet.getLifetime()); break; case UDPPacket.PAYLOAD_TYPE_RELAY_INTRO: if (_log.shouldLog(Log.INFO)) _log.info("Received relay intro packet: " + reader + " from " + from); _introManager.receiveRelayIntro(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.relayIntro", packet.getPacket().getLength(), packet.getLifetime()); break; case UDPPacket.PAYLOAD_TYPE_RELAY_RESPONSE: if (_log.shouldLog(Log.INFO)) _log.info("Received relay response packet: " + reader + " from " + from); _establisher.receiveRelayResponse(from, reader); + _context.statManager().addRateData("udp.receivePacketSize.relayResponse", packet.getPacket().getLength(), packet.getLifetime()); break; default: _state = 52; diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java index ad8bf1f370..13e24c7048 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -1036,7 +1036,7 @@ public class PeerState { remaining = 1; // total lifetime will exceed it anyway, guaranteeing failure float pDrop = totalLifetime / (float)remaining; pDrop = pDrop * pDrop * pDrop; - if (pDrop >= _context.random().nextFloat()) { + if (false && (pDrop >= _context.random().nextFloat())) { if (_log.shouldLog(Log.WARN)) _log.warn("Proactively tail dropping for " + _remotePeer.toBase64() + " (messages=" + msgs.size() + " headLifetime=" + lifetime + " totalLifetime=" + totalLifetime + " curLifetime=" + state.getLifetime() diff --git a/router/java/src/net/i2p/router/transport/udp/UDPSender.java b/router/java/src/net/i2p/router/transport/udp/UDPSender.java index 6ae185b6b0..8b22d180da 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPSender.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPSender.java @@ -55,7 +55,21 @@ public class UDPSender { _context.statManager().createRateStat("udp.sendPacketSize.18", "tunnel data message size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); _context.statManager().createRateStat("udp.sendPacketSize.19", "tunnel gateway message size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); _context.statManager().createRateStat("udp.sendPacketSize.20", "data message size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.21", "tunnel build", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.22", "tunnel build reply", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.20", "data message size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); _context.statManager().createRateStat("udp.sendPacketSize.42", "ack-only packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.43", "hole punch packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.44", "relay response packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.45", "relay intro packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.46", "relay request packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.47", "peer test charlie to bob packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.48", "peer test bob to charlie packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.49", "peer test to alice packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.50", "peer test from alice packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.51", "session confirmed packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.52", "session request packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); + _context.statManager().createRateStat("udp.sendPacketSize.53", "session created packet size", "udp", new long[] { 60*1000, 5*60*1000, 30*60*1000 }); } public void startup() { @@ -211,7 +225,7 @@ public class UDPSender { //_log.debug("Sending packet: (size="+size + "/"+size2 +")\nraw: " + Base64.encode(packet.getPacket().getData(), 0, size)); } - //_context.statManager().addRateData("udp.sendPacketSize." + packet.getMessageType(), size, packet.getFragmentCount()); + _context.statManager().addRateData("udp.sendPacketSize." + packet.getMessageType(), size, packet.getFragmentCount()); //packet.getPacket().setLength(size); try { 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 70814e2ba8..2e83f608a3 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1673,6 +1673,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } if (_alive) { long delay = _context.random().nextInt(2*TEST_FREQUENCY); + if (delay <= 0) + throw new RuntimeException("wtf, delay is " + delay); SimpleTimer.getInstance().addEvent(PeerTestEvent.this, delay); } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java index 9d20b384a6..cfe7aab612 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java @@ -52,7 +52,7 @@ class BuildExecutor implements Runnable { buf = new StringBuffer(128); buf.append("Allowed: "); } - int allowed = 20; + int allowed = 5; String prop = _context.getProperty("router.tunnelConcurrentBuilds"); if (prop != null) try { allowed = Integer.valueOf(prop).intValue(); } catch (NumberFormatException nfe) {} @@ -92,6 +92,8 @@ class BuildExecutor implements Runnable { _context.statManager().addRateData("tunnel.buildExploratoryExpire", 1, 0); else _context.statManager().addRateData("tunnel.buildClientExpire", 1, 0); + for (int j = 0; j < cfg.getLength(); j++) + didNotReply(cfg.getReplyMessageId(), cfg.getPeer(j)); } } @@ -107,11 +109,33 @@ class BuildExecutor implements Runnable { _context.statManager().addRateData("tunnel.concurrentBuildsLagged", concurrent, lag); return 0; // if we have a job heavily blocking our jobqueue, ssllloowww dddooowwwnnn } - //if (isOverloaded()) - // return 0; + + if (isOverloaded()) + return 0; return allowed; } + + /** + * Don't even try to build tunnels if we're saturated + */ + private boolean isOverloaded() { + //if (true) return false; + // dont include the inbound rates when throttling tunnel building, since + // that'd expose a pretty trivial attack. + int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond(); + int used1s = _context.router().get1sRate(true); // dont throttle on the 1s rate, its too volatile + int used1m = _context.router().get1mRate(true); + int used5m = 0; //get5mRate(_context); // don't throttle on the 5m rate, as that'd hide available bandwidth + int used = Math.max(Math.max(used1s, used1m), used5m); + if ((maxKBps * 1024) - used <= 0) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Too overloaded to build our own tunnels (used=" + used + ", maxKBps=" + maxKBps + ", 1s=" + used1s + ", 1m=" + used1m + ")"); + return true; + } else { + return false; + } + } public void run() { _isRunning = true; @@ -306,6 +330,7 @@ class BuildExecutor implements Runnable { _currentlyBuilding.remove(cfg); _currentlyBuilding.notifyAll(); } + long expireBefore = _context.clock().now() + 10*60*1000 - BuildRequestor.REQUEST_TIMEOUT; if (cfg.getExpiration() <= expireBefore) { if (_log.shouldLog(Log.INFO)) @@ -331,6 +356,11 @@ class BuildExecutor implements Runnable { } } + private void didNotReply(long tunnel, Hash peer) { + if (_log.shouldLog(Log.INFO)) + _log.info(tunnel + ": Peer " + peer.toBase64() + " did not reply to the tunnel join request"); + } + List locked_getCurrentlyBuilding() { return _currentlyBuilding; } public int getInboundBuildQueueSize() { return _handler.getInboundBuildQueueSize(); } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java index aa426c51a4..7c0b144d8b 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java @@ -213,8 +213,8 @@ class BuildHandler { Hash peer = cfg.getPeer(i); int record = order.indexOf(new Integer(i)); int howBad = statuses[record]; - if (_log.shouldLog(Log.DEBUG)) - _log.debug(msg.getUniqueId() + ": Peer " + peer.toBase64() + " replied with status " + howBad); + if (_log.shouldLog(Log.INFO)) + _log.info(msg.getUniqueId() + ": Peer " + peer.toBase64() + " replied with status " + howBad); if (howBad == 0) { // w3wt @@ -415,7 +415,7 @@ class BuildHandler { int proactiveDrops = countProactiveDrops(); long recvDelay = System.currentTimeMillis()-state.recvTime; if (response == 0) { - float pDrop = recvDelay / (BuildRequestor.REQUEST_TIMEOUT/2); + float pDrop = recvDelay / (BuildRequestor.REQUEST_TIMEOUT); pDrop = (float)Math.pow(pDrop, 16); if (_context.random().nextFloat() < pDrop) { // || (proactiveDrops > MAX_PROACTIVE_DROPS) ) ) { _context.statManager().addRateData("tunnel.rejectOverloaded", recvDelay, proactiveDrops); @@ -547,6 +547,8 @@ class BuildHandler { } } + /** um, this is bad. don't set this. */ + private static final boolean DROP_ALL_REQUESTS = false; private static final boolean HANDLE_REPLIES_INLINE = true; private class TunnelBuildMessageHandlerJobBuilder implements HandlerJobBuilder { @@ -586,7 +588,7 @@ class BuildHandler { _exec.repoll(); } } else { - if (_exec.wasRecentlyBuilding(reqId)) { + if (DROP_ALL_REQUESTS || _exec.wasRecentlyBuilding(reqId)) { if (_log.shouldLog(Log.WARN)) _log.warn("Dropping the reply " + reqId + ", as we used to be building that"); } else { @@ -608,7 +610,7 @@ class BuildHandler { _context.statManager().addRateData("tunnel.dropLoadBacklog", _inboundBuildMessages.size(), _inboundBuildMessages.size()); } else { int queueTime = estimateQueueTime(_inboundBuildMessages.size()); - float pDrop = queueTime/((float)BuildRequestor.REQUEST_TIMEOUT/2); + float pDrop = queueTime/((float)BuildRequestor.REQUEST_TIMEOUT); pDrop = (float)Math.pow(pDrop, 16); // steeeep float f = _context.random().nextFloat(); if ( (pDrop > f) && (allowProactiveDrop()) ) { -- GitLab