diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index ec5e2b8dbedc31df0a93c1966414a76e7db07405..85497d4f73ed53aca94ffaaacc1d9d8b32ec54cb 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -512,7 +512,8 @@ public class I2PSnarkServlet extends HttpServlet {
                 Map.Entry entry = (Map.Entry)iter.next();
                 String name = (String)entry.getKey();
                 String baseURL = (String)entry.getValue();
-                if (!baseURL.startsWith(announce))
+                if (!(baseURL.startsWith(announce) || // vvv hack for non-b64 announce in list vvv
+                      (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/"))))
                     continue;
                 int e = baseURL.indexOf('=');
                 if (e < 0)
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java
index 643c8c45c35bbdf4b736e8ee4b013340a677c9e6..6b3916883a85945464c92583946f44698c99a915 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java
@@ -9,12 +9,17 @@ public class CSSHelper extends HelperBase {
     
     public static final String PROP_THEME_NAME = "routerconsole.theme";
     private static final String BASE = "/themes/console/";
+    private static final String FORCE = "classic";
 
-    public String getTheme() {
+    public String getTheme(String userAgent) {
         String url = BASE;
-        String theme = _context.getProperty(PROP_THEME_NAME);
-        if (theme != null)
-            url += theme + "/";
+        if (userAgent != null && userAgent.contains("MSIE")) {
+            url += FORCE + "/";
+        } else {
+            String theme = _context.getProperty(PROP_THEME_NAME);
+            if (theme != null)
+                url += theme + "/";
+        }
         return url;
     }
 }
diff --git a/apps/routerconsole/jsp/css.jsp b/apps/routerconsole/jsp/css.jsp
index 1e47f34d4cf879b400819dc654b3163b81777e24..60db0683502fde79a72f1a69da4784af8525234c 100644
--- a/apps/routerconsole/jsp/css.jsp
+++ b/apps/routerconsole/jsp/css.jsp
@@ -17,4 +17,4 @@
 %>
 <jsp:useBean class="net.i2p.router.web.CSSHelper" id="cssHelper" scope="request" />
 <jsp:setProperty name="cssHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
-<link href="<%=cssHelper.getTheme()%>console.css" rel="stylesheet" type="text/css" /> 
+<link href="<%=cssHelper.getTheme(request.getHeader("User-Agent"))%>console.css" rel="stylesheet" type="text/css" /> 
diff --git a/history.txt b/history.txt
index f6685137248337a23db15cd3774aebbcdde90a23..ff18e294e9501086c41a3cac77a912e1108ce3ef 100644
--- a/history.txt
+++ b/history.txt
@@ -5,6 +5,28 @@
 				added to advanced config.
 				      
 2009-07-07 dr|z3d
+2009-07-07  dr|z3d
+2009-07-11 zzz
+    * Build Handler: Drop rather than reject requests when near
+      conn limits and the next hop is not connected, to reduce
+      connection congestion
+    * Console: Force IE to the classic theme
+    * I2PSnark:
+      - Bring back details links for Postman2 B64 torrents
+    * I2PTunnel:
+      - Make reduce-on-idle the default for all the shared clients
+        for new installs (15m)
+    * Profile Organizer:
+      - Allow NTCP-only peers in inbound tunnels
+    * Transports:
+      - Move from a single connection limit threshold (80%) to
+        two (75% and 87%), and only start rejecting tunnels
+        at the higher threshold, to increase build success
+      - Move some limit methods from the transports to TransportImpl
+      - Add limit methods with a threshold argument
+      - Increase default SSU conn limits a little more
+
+2009-07-07  dr|z3d
     * Introducing 2 new console themes (light & dark), in addition
       to changes to the console navigation; navbar now resides in 
       the sidepanel and other stuff besides. More to follow!
diff --git a/installer/resources/i2ptunnel.config b/installer/resources/i2ptunnel.config
index 2f811ebde39873967350f533d0d3f01781f602ee..f1fe7cda2edd3e7310a3a91aa11224a6de7feeee 100644
--- a/installer/resources/i2ptunnel.config
+++ b/installer/resources/i2ptunnel.config
@@ -10,6 +10,9 @@ tunnel.0.i2cpHost=127.0.0.1
 tunnel.0.i2cpPort=7654
 tunnel.0.option.inbound.nickname=shared clients
 tunnel.0.option.outbound.nickname=shared clients
+tunnel.0.option.i2cp.reduceIdleTime=900000
+tunnel.0.option.i2cp.reduceOnIdle=true
+tunnel.0.option.i2cp.reduceQuantity=1
 tunnel.0.option.i2p.streaming.connectDelay=1000
 tunnel.0.startOnLoad=true
 
@@ -25,6 +28,9 @@ tunnel.1.i2cpHost=127.0.0.1
 tunnel.1.i2cpPort=7654
 tunnel.1.option.inbound.nickname=shared clients
 tunnel.1.option.outbound.nickname=shared clients
+tunnel.1.option.i2cp.reduceIdleTime=900000
+tunnel.1.option.i2cp.reduceOnIdle=true
+tunnel.1.option.i2cp.reduceQuantity=1
 tunnel.1.option.i2p.streaming.connectDelay=1000
 tunnel.1.option.i2p.streaming.maxWindowSize=16
 tunnel.1.startOnLoad=true
@@ -41,6 +47,9 @@ tunnel.2.i2cpHost=127.0.0.1
 tunnel.2.i2cpPort=7654
 tunnel.2.option.inbound.nickname=shared clients
 tunnel.2.option.outbound.nickname=shared clients
+tunnel.2.option.i2cp.reduceIdleTime=900000
+tunnel.2.option.i2cp.reduceOnIdle=true
+tunnel.2.option.i2cp.reduceQuantity=1
 tunnel.2.startOnLoad=false
 
 # local eepserver
@@ -70,6 +79,9 @@ tunnel.4.listenPort=7659
 tunnel.4.name=smtp.postman.i2p
 tunnel.4.option.inbound.nickname=shared clients
 tunnel.4.option.outbound.nickname=shared clients
+tunnel.4.option.i2cp.reduceIdleTime=900000
+tunnel.4.option.i2cp.reduceOnIdle=true
+tunnel.4.option.i2cp.reduceQuantity=1
 tunnel.4.option.i2p.streaming.connectDelay=1000
 tunnel.4.startOnLoad=true
 tunnel.4.targetDestination=smtp.postman.i2p
@@ -85,6 +97,9 @@ tunnel.5.interface=127.0.0.1
 tunnel.5.listenPort=7660
 tunnel.5.option.inbound.nickname=shared clients
 tunnel.5.option.outbound.nickname=shared clients
+tunnel.5.option.i2cp.reduceIdleTime=900000
+tunnel.5.option.i2cp.reduceOnIdle=true
+tunnel.5.option.i2cp.reduceQuantity=1
 tunnel.5.option.i2p.streaming.connectDelay=1000
 tunnel.5.startOnLoad=true
 tunnel.5.targetDestination=pop.postman.i2p
diff --git a/readme.html b/readme.html
index 3b95e801aa8609611b56e06fd6831896b79c9390..4026bc867de4efdbfbb3e3104f9fab716b1aecce 100644
--- a/readme.html
+++ b/readme.html
@@ -75,6 +75,4 @@ You may also want to review the information on the
 <a href="http://www.i2p2.i2p/">I2P website</a>, post up messages to the 
 <a href="http://forum.i2p2.de/">I2P discussion forum</a>, or swing by #i2p or
 #i2p-chat on IRC at <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p or irc.freshcoffee.i2p (they're linked together).</p>
-
-<p><b>As a note, you can change this page by editing the file "docs/readme.html"</b></p>
-</div>
\ No newline at end of file
+</div>
diff --git a/readme_de.html b/readme_de.html
index 60d8aeabe0239f8fc8b91f919c325062c1bc3e88..885ac923a0abb493d2ef59415a8c493f6a627e36 100644
--- a/readme_de.html
+++ b/readme_de.html
@@ -72,5 +72,3 @@
   chatten auf #i2p or #i2p-chat beim IRC auf 
   <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p 
   oder irc.freshcoffee.i2p (die verbunden sind).</p>
-
-<p><b>&Uuml;brigens, diese Seite kannst Du &auml;ndern indem Du "docs/readme_de.html" editierst</b></p>
diff --git a/readme_fr.html b/readme_fr.html
index 9ab143e4adc90b9ba540fa3665719df71d6107f6..f5112970da0630d21a21409b0d4a964a56015dcd 100644
--- a/readme_fr.html
+++ b/readme_fr.html
@@ -37,5 +37,3 @@
 <h2><a name="trouble">D&eacute;pannage</a></h2>
 
 <p>Soyez patient - i2p peut s'av&eacute;rer lent &agrave; d&eacute;marrer la premi&egrave;re fois car il recherche des pairs. Si, apr&egrave;s 30 minutes, votre Actives: connect&eacute;/r&eacute;cent compte moins de 10 pairs connect&eacute;s, vous devez ouvrir le port 8887 sur votre pare-feu pour avoir une meilleure connection. Si vous ne pouvez acc&eacute;der &agrave; aucun eepsite (m&ecirc;me <a href="http://www.i2p2.i2p/">www.i2p2.i2p</a>), soyez s&ucirc;r que votre navigateur utilise bien le proxy localhost sur le port 4444. Vous pouvez aussi faire part de votre d&eacute;marche sur le <a href="http://www.i2p2.i2p/">site web I2P</a>, poster des message sur le <a href="http://forum.i2p/">forum de discussion</a>, ou passer par #i2p ou #i2p-chat sur IRC sur le serveur <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p ou irc.freshcoffee.i2p (ils sont li&eacute;s).</p>
-
-<p><b>Comme vous pouvez le remarquer, il suffit d'&eacute;diter la page "docs/readme.html" pour changer la page d'acceuil</b></p>
diff --git a/readme_nl.html b/readme_nl.html
index 7ff79e89dcd6a3d1f66bf0c9d40735e02a19dfc0..296e2c496ee8f87a9e97f054a4c7173ad5f1f239 100644
--- a/readme_nl.html
+++ b/readme_nl.html
@@ -56,5 +56,3 @@ Je zou best ook de informatie controleren op de
 <a href="http://www.i2p2.i2p/">I2P website</a>, of plaats een bericht op het
 <a href="http://forum.i2p/">I2P discussie forum</a>, of kom langs bij #i2p of
 #i2p-chat op IRC bij de kanalen <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p of irc.freshcoffee.i2p (ze linken allemaal door naar elkaar).</p>
-
-<p><b>Als extra informatie, je kan deze pagina wijzigen door het bestand "docs/readme_nl.html" aan te passen.</b></p>
diff --git a/readme_sv.html b/readme_sv.html
index ef68ea14eee293726a27a79e7d10cbc1796475e7..7d738aa126e05132fae884a60dc2b49f42020f3a 100644
--- a/readme_sv.html
+++ b/readme_sv.html
@@ -98,6 +98,3 @@ f&ouml;rbi #i2p eller
 #i2p-chat p&aring; IRC p� <a 
 href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p 
 eller irc.freshcoffee.i2p (de &auml;r alla sammankopplade).</p>
-
-<p><b>Du kan f&ouml;r&auml;ndra denh&auml;r sidan genom att &auml;ndra i filen 
-"docs/readme_sv.html"</b></p>
diff --git a/readme_zh.html b/readme_zh.html
index 6f2a0394c8691de38be1b5a84ff2a43b823a141e..bb7dc314a787b25f7f38ea9904dfe87e18c4a8cc 100644
--- a/readme_zh.html
+++ b/readme_zh.html
@@ -24,5 +24,3 @@
 <h2><a name="trouble">���ѽ��</a></h2>
 
 <p>�������� - I2P ��һ������ʱ��Ҫ�����ڵ㣬���ܱȽϻ��������30���Ӻ����Ļ�ڵ�(Active:������/�½�����) �������� 10 ���ڵ�����, ���ڷ���ǽ�д� 8887 �˿ڸ����������ܡ�����������޷����κ�EEPSITE(���� <a href="http://www.i2p2.i2p/">www.i2p2.i2p</a>)�����������������������Ƿ�Ϊ���ص� localhost:4444����Ҳ���Բ鿴 <a href="http://www.i2p2.i2p/">I2P ��վ</a> �ϵ���Ϣ, �� <a href="http://forum.i2p2.de/">I2P ��̳</a> �з���, �� <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a> , irc.postman.i2p �� irc.freshcoffee.i2p �ϵ� #i2p �� #i2p-chat ����IRCƵ�������� (��Щ�������ϵ�������Ƶ������ͨ��)��</p>
-
-<p><B>��ʾ��������ͨ���༭ &quot;docs/readme_zh.html&quot; �޸ı�ҳ�档</B></p>
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/networkdb/reseed/ReseedChecker.java b/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java
index aa38be5e7c6462efaa493cfb327deee0b5bce2c9..dd11c4ae2145178c5fc1fbc75cd5d1f86c12c5db 100644
--- a/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java
+++ b/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java
@@ -15,8 +15,7 @@ import net.i2p.util.Log;
  *
  *  Also, as this is now called from PersistentDataStore, not from the
  *  routerconsole, we can get started as soon as the netdb has read
- *  the netDb/ directory, not when the console starts,
-router/java/src/net/i2p/router/networkdb/eseed/ReseedChecker.java
+ *  the netDb/ directory, not when the console starts.
  */
 public class ReseedChecker {
     
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
index 90792571e33a21580737955d7b2b0830cc53e5a0..504c5670300827ea2c7f6efdd893debcef22c2da 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
@@ -541,9 +541,11 @@ public class ProfileOrganizer {
                         l.add(peer);
                     else {
                         RouterAddress ra = info.getTargetAddress("SSU");
-                        // Definitely don't want peers with no SSU address at all
+                        // peers with no SSU address at all are fine.
+                        // as long as they have NTCP
                         if (ra == null) {
-                            l.add(peer);
+                            if (info.getTargetAddress("NTCP") == null)
+                                l.add(peer);
                             continue;
                         }
                         // This is the quick way of doing UDPAddress.getIntroducerCount() > 0
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index 9067aad937cd1a2f3ce73f019b04924af2c252d8..60e2af05ce02c540016791c9f7f8e0611c67d797 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..29318bb604f69e9c0b414b951f400b5ba3e072c9 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; }
     /**
@@ -108,14 +113,22 @@ public abstract class TransportImpl implements Transport {
         }
         // increase limit for SSU, for now
         if (style.equals("udp"))
-            def = def * 4 / 3;
+            def = def * 3 / 2;
         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 0583c73b118fb4bb66a87c3a5a17c50f8a959623..ae17622e85661daa443b47d4ecc795cc6ca4de67 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
@@ -65,6 +65,7 @@ class BuildHandler {
 
         _context.statManager().createRateStat("tunnel.rejectOverloaded", "How long we had to wait before processing the request (when it was rejected)", "Tunnels", new long[] { 60*1000, 10*60*1000 });
         _context.statManager().createRateStat("tunnel.acceptLoad", "Delay before processing the accepted request", "Tunnels", new long[] { 60*1000, 10*60*1000 });
+        _context.statManager().createRateStat("tunnel.dropConnLimits", "Drop instead of reject due to conn limits", "Tunnels", new long[] { 60*1000, 10*60*1000 });
         _context.statManager().createRateStat("tunnel.dropLoad", "How long we had to wait before finally giving up on an inbound request (period is queue count)?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
         _context.statManager().createRateStat("tunnel.dropLoadDelay", "How long we had to wait before finally giving up on an inbound request?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
         _context.statManager().createRateStat("tunnel.dropLoadBacklog", "How many requests were pending when they were so lagged that we had to drop a new inbound request??", "Tunnels", new long[] { 60*1000, 10*60*1000 });
@@ -466,7 +467,6 @@ class BuildHandler {
         return 0;
     }
     
-    private static final String PROP_REJECT_NONPARTICIPANT = "router.participantOnly";
     private void handleReq(RouterInfo nextPeerInfo, BuildMessageState state, BuildRequestRecord req, Hash nextPeer) {
         long ourId = req.readReceiveTunnelId();
         long nextId = req.readNextTunnelId();
@@ -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;
         }
@@ -569,6 +569,17 @@ class BuildHandler {
                                                      (isOutEnd ? "outbound endpoint" : isInGW ? "inbound gw" : "participant"));
         }
 
+        // Connection congestion control:
+        // If we rejected the request, are near our conn limits, and aren't connected to the next hop,
+        // just drop it.
+        if (response != 0 &&
+            (! _context.routerHash().equals(nextPeer)) &&
+            (! _context.commSystem().haveOutboundCapacity(75)) &&
+            (! _context.commSystem().isEstablished(nextPeer))) {
+            _context.statManager().addRateData("tunnel.dropConnLimits", 1, 0);
+            return;
+        }
+
         BuildResponseRecord resp = new BuildResponseRecord();
         byte reply[] = resp.create(_context, response, req.readReplyKey(), req.readReplyIV(), state.msg.getUniqueId());
         for (int j = 0; j < TunnelBuildMessage.RECORD_COUNT; j++) {