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