diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java
index c26d9efbf78d95a166572c2b771ab773e584fcd0..e8a45724e0a12af3179c821395d4e5fe9f0624e2 100644
--- a/router/java/src/net/i2p/router/CommSystemFacade.java
+++ b/router/java/src/net/i2p/router/CommSystemFacade.java
@@ -34,8 +34,8 @@ public abstract class CommSystemFacade implements Service {
     
     public int countActivePeers() { return 0; }
     public int countActiveSendPeers() { return 0; }
-    public boolean haveInboundCapacity() { return true; }
-    public boolean haveOutboundCapacity() { return true; }
+    public boolean haveInboundCapacity(int pct) { return true; }
+    public boolean haveOutboundCapacity(int pct) { return true; }
     public boolean haveHighOutboundCapacity() { return true; }
     public List getMostRecentErrorMessages() { return Collections.EMPTY_LIST; }
     
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index a426c45304e0150d838f6fa013aa6b8df3f39606..6c9d08e2c74e94cd833bb7f195992093390989c2 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -70,9 +70,9 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
     @Override
     public int countActiveSendPeers() { return (_manager == null ? 0 : _manager.countActiveSendPeers()); } 
     @Override
-    public boolean haveInboundCapacity() { return (_manager == null ? false : _manager.haveInboundCapacity()); } 
+    public boolean haveInboundCapacity(int pct) { return (_manager == null ? false : _manager.haveInboundCapacity(pct)); } 
     @Override
-    public boolean haveOutboundCapacity() { return (_manager == null ? false : _manager.haveOutboundCapacity()); } 
+    public boolean haveOutboundCapacity(int pct) { return (_manager == null ? false : _manager.haveOutboundCapacity(pct)); } 
     @Override
     public boolean haveHighOutboundCapacity() { return (_manager == null ? false : _manager.haveHighOutboundCapacity()); } 
     
diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java
index d0ec7267b356bd6902023e72b9e8ccd67b6fddb0..339c33f7be050b26b87c0cfdfbd47e47c93f7859 100644
--- a/router/java/src/net/i2p/router/transport/Transport.java
+++ b/router/java/src/net/i2p/router/transport/Transport.java
@@ -44,10 +44,11 @@ public interface Transport {
     public void setListener(TransportEventListener listener);
     public String getStyle();
     
+    public int countPeers();    
     public int countActivePeers();    
     public int countActiveSendPeers();
     public boolean haveCapacity();
-    public boolean haveHighCapacity();
+    public boolean haveCapacity(int pct);
     public Vector getClockSkews();
     public List getMostRecentErrorMessages();
     
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index 7f27766a76f0bc7333faa61259ceabc9c083f9a3..1923e1ec71b4e4b0c8f521bb9bb8461ac6a1d98b 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -78,8 +78,13 @@ public abstract class TransportImpl implements Transport {
     }
 
     /**
-     * How many peers can we talk to right now?
-     *
+     * How many peers are we connected to?
+     * For NTCP, this is the same as active,
+     * but SSU actually looks at idle time for countActivePeers()
+     */
+    public int countPeers() { return countActivePeers(); }
+    /**
+     * How many peers active in the last few minutes?
      */
     public int countActivePeers() { return 0; }
     /**
@@ -112,10 +117,18 @@ public abstract class TransportImpl implements Transport {
         return _context.getProperty("i2np." + style + ".maxConnections", def);
     }
 
+    private static final int DEFAULT_CAPACITY_PCT = 75;
     /**
      * Can we initiate or accept a connection to another peer, saving some margin
      */
-    public boolean haveCapacity() { return true; }
+    public boolean haveCapacity() {
+        return haveCapacity(DEFAULT_CAPACITY_PCT);
+    }
+
+    /** @param pct are we under x% 0-100 */
+    public boolean haveCapacity(int pct) {
+        return countPeers() < getMaxConnections() * pct / 100;
+    }
 
     /**
      * Return our peer clock skews on a transport.
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index d432f80fd2d0e7cd4a585f3896392b414da4ec5e..f9d495cea1d97ff7c5b85041cc8098037fddfed9 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -206,15 +206,18 @@ public class TransportManager implements TransportEventListener {
     /**
       * Is at least one transport below its outbound connection limit + some margin
       * Use for throttling in the router.
+      *
+      * @param pct percent of limit 0-100
       */
-    public boolean haveOutboundCapacity() { 
+    public boolean haveOutboundCapacity(int pct) { 
         for (int i = 0; i < _transports.size(); i++) {
-            if (((Transport)_transports.get(i)).haveCapacity())
+            if (((Transport)_transports.get(i)).haveCapacity(pct))
                 return true;
         }
         return false;
     }
     
+    private static final int HIGH_CAPACITY_PCT = 50;
     /**
       * Are all transports well below their outbound connection limit
       * Use for throttling in the router.
@@ -223,7 +226,7 @@ public class TransportManager implements TransportEventListener {
         if (_transports.size() <= 0)
             return false;
         for (int i = 0; i < _transports.size(); i++) {
-            if (!((Transport)_transports.get(i)).haveHighCapacity())
+            if (!((Transport)_transports.get(i)).haveCapacity(HIGH_CAPACITY_PCT))
                 return false;
         }
         return true;
@@ -232,10 +235,12 @@ public class TransportManager implements TransportEventListener {
     /**
       * Is at least one transport below its inbound connection limit + some margin
       * Use for throttling in the router.
+      *
+      * @param pct percent of limit 0-100
       */
-    public boolean haveInboundCapacity() { 
+    public boolean haveInboundCapacity(int pct) { 
         for (int i = 0; i < _transports.size(); i++) {
-            if (_transports.get(i).getCurrentAddress() != null && _transports.get(i).haveCapacity())
+            if (_transports.get(i).getCurrentAddress() != null && _transports.get(i).haveCapacity(pct))
                 return true;
         }
         return false;
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index 5fa10b3108c47049eadb42bd0fd88177256561f4..bd300112b2b850761370b32b2b707893543b30ba 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -321,15 +321,6 @@ public class NTCPTransport extends TransportImpl {
         return countActivePeers() < getMaxConnections();
     }
 
-    @Override
-    public boolean haveCapacity() {
-        return countActivePeers() < getMaxConnections() * 4 / 5;
-    }
-
-    public boolean haveHighCapacity() {
-        return countActivePeers() < getMaxConnections() / 2;
-    }
-
     /** queue up afterSend call, which can take some time w/ jobs, etc */
     void sendComplete(OutNetMessage msg) { _finisher.add(msg); }
 
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 47edd62c3af35b00442524a5ce83fcd430da1813..97d1e3ba45100fd169cc7a72eaf0f7f943aafb85 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -1334,6 +1334,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             super.afterSend(m, true);
     }
 
+    @Override
+    public int countPeers() {
+        synchronized (_peersByIdent) {
+            return _peersByIdent.size();
+        }
+    }
+
     @Override
     public int countActivePeers() {
         long now = _context.clock().now();
@@ -1379,19 +1386,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         }
     }
 
-    @Override
-    public boolean haveCapacity() {
-        synchronized (_peersByIdent) {
-            return _peersByIdent.size() < getMaxConnections() * 4 / 5;
-        }
-    }
-
-    public boolean haveHighCapacity() {
-        synchronized (_peersByIdent) {
-            return _peersByIdent.size() < getMaxConnections() / 2;
-        }
-    }
-
     /**
      * Return our peer clock skews on this transport.
      * Vector composed of Long, each element representing a peer skew in seconds.
diff --git a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java
index de29a9540ff8e89706600c8dbd39372e97f94dd7..3da777076c10bfa131941dc9f4bdaabf2195d4f6 100644
--- a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java
+++ b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java
@@ -253,6 +253,12 @@ public class TunnelDispatcher implements Service {
         return _participatingConfig.size();
     }
     
+    /*******  may be used for congestion control later...
+    public int getParticipatingInboundGatewayCount() {
+        return _inboundGateways.size();
+    }
+    *******/
+    
     /** what is the date/time on which the last non-locally-created tunnel expires? */
     public long getLastParticipatingExpiration() { return _lastParticipatingExpiration; }
     
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 1d0f4f54c8a69f5afc86f17c9a8d5d108b6cf48c..ae17622e85661daa443b47d4ecc795cc6ca4de67 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
@@ -510,8 +510,8 @@ class BuildHandler {
          * reject this request.
          */
         if (response == 0 &&
-            ((isInGW && ! _context.commSystem().haveInboundCapacity()) ||
-             (isOutEnd && ! _context.commSystem().haveOutboundCapacity()))) {
+            ((isInGW && ! _context.commSystem().haveInboundCapacity(87)) ||
+             (isOutEnd && ! _context.commSystem().haveOutboundCapacity(87)))) {
                 _context.throttle().setTunnelStatus("Rejecting tunnels: Connection limit");
                 response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
         }
@@ -574,7 +574,7 @@ class BuildHandler {
         // just drop it.
         if (response != 0 &&
             (! _context.routerHash().equals(nextPeer)) &&
-            (! _context.commSystem().haveOutboundCapacity()) &&
+            (! _context.commSystem().haveOutboundCapacity(75)) &&
             (! _context.commSystem().isEstablished(nextPeer))) {
             _context.statManager().addRateData("tunnel.dropConnLimits", 1, 0);
             return;