diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
index 12df19d01babe18e6f998c60a28331ca7b45eebc..c5ebb16cf91a538b68963f6e2026018739ac6a07 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
@@ -5,6 +5,7 @@ import net.i2p.router.RouterContext;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.data.RouterAddress;
 import net.i2p.router.transport.udp.UDPAddress;
+import net.i2p.router.transport.udp.UDPTransport;
 
 public class ConfigNetHelper {
     private RouterContext _context;
@@ -66,11 +67,15 @@ public class ConfigNetHelper {
         short status = _context.commSystem().getReachabilityStatus();
         switch (status) {
             case CommSystemFacade.STATUS_OK:
+                if ("true".equalsIgnoreCase(_context.getProperty(UDPTransport.PROP_FORCE_INTRODUCERS, "false")))
+                    return "checked=\"true\"";
                 return "";
             case CommSystemFacade.STATUS_DIFFERENT:
             case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
                 return "checked=\"true\"";
             case CommSystemFacade.STATUS_UNKNOWN:
+                if ("true".equalsIgnoreCase(_context.getProperty(UDPTransport.PROP_FORCE_INTRODUCERS, "false")))
+                    return "checked=\"true\"";
                 return "";
             default:
                 return "checked=\"true\"";
diff --git a/apps/routerconsole/jsp/summary.jsp b/apps/routerconsole/jsp/summary.jsp
index 4fa834e5aa2047561a5d43926b758ac0ed416e50..8fb1bf414e23b7fc7bfe6cb2b758aec7d506d36b 100644
--- a/apps/routerconsole/jsp/summary.jsp
+++ b/apps/routerconsole/jsp/summary.jsp
@@ -40,7 +40,7 @@
  <b>High capacity:</b> <jsp:getProperty name="helper" property="highCapacityPeers" /><br />
  <b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br />
  <b>Failing:</b> <jsp:getProperty name="helper" property="failingPeers" /><br />
- <b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br />
+ <!-- <b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br /> -->
  <b>Known:</b> <jsp:getProperty name="helper" property="allPeers" /><br /><%
      if (helper.getActivePeers() <= 0) {
         %><b><a href="config.jsp">check your NAT/firewall</a></b><br /><%
diff --git a/history.txt b/history.txt
index ebebc0339a75b72a6ea2f09f341b00df252e854e..7efc7ee0608a5f250e1dfaed539c2a301ff8c3ba 100644
--- a/history.txt
+++ b/history.txt
@@ -1,4 +1,9 @@
-$Id: history.txt,v 1.247 2005/09/12 22:32:30 jrandom Exp $
+$Id: history.txt,v 1.248 2005/09/13 04:06:07 comwiz Exp $
+
+2005-09-13  jrandom
+    * More careful error handling with introductions (thanks dust!)
+    * Fix the forceIntroducers checkbox on config.jsp (thanks Complication!)
+    * Hide the shitlist on the summary so it doesn't confuse new users.
 
 2005-09-12  comwiz
     * Migrated the router tests to junit
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 4384bda4db2f594d7f55d9afa2daccf24cac74bf..6efac719969a66dfecbd5b19bc554e6fd586b06c 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.233 $ $Date: 2005/09/12 20:12:43 $";
+    public final static String ID = "$Revision: 1.234 $ $Date: 2005/09/12 22:32:30 $";
     public final static String VERSION = "0.6.0.5";
-    public final static long BUILD = 8;
+    public final static long BUILD = 9;
     public static void main(String args[]) {
         System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
         System.out.println("Router ID: " + RouterVersion.ID);
diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
index 62acf62567ea56471a60448183a7c5bb6ca1f142..1679b425649567cea21bb9b25500bd2ff2b06504 100644
--- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
@@ -764,36 +764,46 @@ public class EstablishmentManager {
     private class Establisher implements Runnable {
         public void run() {
             while (_alive) {
-                _activity = 0;
-                long now = _context.clock().now();
-                long nextSendTime = -1;
-                long nextSendInbound = handleInbound();
-                long nextSendOutbound = handleOutbound();
-                if (nextSendInbound > 0)
-                    nextSendTime = nextSendInbound;
-                if ( (nextSendTime < 0) || (nextSendOutbound < nextSendTime) )
-                    nextSendTime = nextSendOutbound;
+                try {
+                    doPass();
+                } catch (OutOfMemoryError oom) {
+                    throw oom;
+                } catch (RuntimeException re) {
+                    _log.log(Log.CRIT, "Error in the establisher", re);
+                }
+            }
+        }
+    }
+    
+    private void doPass() {
+        _activity = 0;
+        long now = _context.clock().now();
+        long nextSendTime = -1;
+        long nextSendInbound = handleInbound();
+        long nextSendOutbound = handleOutbound();
+        if (nextSendInbound > 0)
+            nextSendTime = nextSendInbound;
+        if ( (nextSendTime < 0) || (nextSendOutbound < nextSendTime) )
+            nextSendTime = nextSendOutbound;
 
-                long delay = nextSendTime - now;
-                if ( (nextSendTime == -1) || (delay > 0) ) {
-                    boolean interrupted = false;
-                    try {
-                        synchronized (_activityLock) {
-                            if (_activity > 0)
-                                continue;
-                            if (nextSendTime == -1)
-                                _activityLock.wait();
-                            else
-                                _activityLock.wait(delay);
-                        }
-                    } catch (InterruptedException ie) {
-                        interrupted = true;
-                    }
-                    if (_log.shouldLog(Log.DEBUG))
-                        _log.debug("After waiting w/ nextSend=" + nextSendTime 
-                                   + " and delay=" + delay + " and interrupted=" + interrupted);
+        long delay = nextSendTime - now;
+        if ( (nextSendTime == -1) || (delay > 0) ) {
+            boolean interrupted = false;
+            try {
+                synchronized (_activityLock) {
+                    if (_activity > 0)
+                        return;
+                    if (nextSendTime == -1)
+                        _activityLock.wait();
+                    else
+                        _activityLock.wait(delay);
                 }
+            } catch (InterruptedException ie) {
+                interrupted = true;
             }
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("After waiting w/ nextSend=" + nextSendTime 
+                           + " and delay=" + delay + " and interrupted=" + interrupted);
         }
     }
 }
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 3eedc3b80db43dc37bf07853155d262cf568484e..9b0eb07689c185e23a5937027ebd43af868eab96 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
@@ -641,11 +641,20 @@ public class PacketBuilder {
     
     public UDPPacket buildRelayRequest(OutboundEstablishState state, SessionKey ourIntroKey) {
         UDPAddress addr = state.getRemoteAddress();
-        int index = _context.random().nextInt(UDPAddress.MAX_INTRODUCERS) % addr.getIntroducerCount();
+        int count = addr.getIntroducerCount();
+        if (count <= 0)
+            return null;
+        int index = _context.random().nextInt(count);
         InetAddress iaddr = addr.getIntroducerHost(index);
         int iport = addr.getIntroducerPort(index);
         byte ikey[] = addr.getIntroducerKey(index);
         long tag = addr.getIntroducerTag(index);
+        if ( (ikey == null) || (iport <= 0) || (iaddr == null) || (tag <= 0) ) {
+            if (_log.shouldLog(_log.ERROR))
+                _log.error("Cannot build a relay request to " + state.getRemoteIdentity().calculateHash().toBase64() 
+                           + ", as their UDP address is invalid: addr=" + addr + " index=" + index);
+            return null;
+        }
         return buildRelayRequest(iaddr, iport, ikey, tag, ourIntroKey, state.getIntroNonce(), true);
     }
     
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
index eff77968e1833c19e0d134b5057398eaf9ee13e1..66b8562448d5267f84cdfcac79bc686dcd54fbd0 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
@@ -422,7 +422,7 @@ class PeerTestManager {
             aliceIP = InetAddress.getByAddress(from.getIP());
             aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
             testInfo.readIntroKey(aliceIntroKey.getData(), 0);
-            
+
             UDPAddress addr = new UDPAddress(charlieInfo.getTargetAddress(UDPTransport.STYLE));
             SessionKey charlieIntroKey = new SessionKey(addr.getIntroKey());
             
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPAddress.java b/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
index bca6884b0b8fb6e553760ae5c9f4def9a1e1e257..2ea29a4e5bdbf3ebfec49b597b26192cb0bc4365 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
@@ -61,6 +61,7 @@ public class UDPAddress {
     }
     
     private void parse(RouterAddress addr) {
+        if (addr == null) return;
         Properties opts = addr.getOptions();
         _host = opts.getProperty(PROP_HOST);
         if (_host != null) _host = _host.trim();
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 2be15f3258ce94a4124d67e9682212a974bfe328..a863092cb587eee08cbd55e2daad0304c31fa237 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -1173,7 +1173,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             PeerState peer = (PeerState)peers.get(i);
             if ( (dontInclude != null) && (dontInclude.equals(peer.getRemoteHostId())) )
                 continue;
-            return peer;
+            RouterInfo peerInfo = _context.netDb().lookupRouterInfoLocally(peer.getRemotePeer());
+            if (peerInfo == null)
+                continue;
+            RouterAddress addr = peerInfo.getTargetAddress(STYLE);
+            if (addr != null)
+                return peer;
         }
         return null;
     }
diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
index e8f81d50b494fb488055bd320120c9e0e206def7..5a0cb91f2f0ab9baeef5d432298adb75b237224a 100644
--- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
@@ -90,6 +90,8 @@ public class FragmentHandler {
                 }
                 offset = off;
             }
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
         } catch (RuntimeException e) {
             if (_log.shouldLog(Log.ERROR))
                 _log.error("Corrupt fragment received: offset = " + offset, e);
@@ -216,17 +218,23 @@ public class FragmentHandler {
         long messageId = -1;
         
         if (type == TYPE_TUNNEL) {
+            if (offset + 4 >= preprocessed.length)
+                return -1;
             long id = DataHelper.fromLong(preprocessed, offset, 4);
             tunnelId = new TunnelId(id);
             offset += 4;
         }
         if ( (type == TYPE_ROUTER) || (type == TYPE_TUNNEL) ) {
             byte h[] = new byte[Hash.HASH_LENGTH];
+            if (offset + Hash.HASH_LENGTH >= preprocessed.length)
+                return -1;
             System.arraycopy(preprocessed, offset, h, 0, Hash.HASH_LENGTH);
             router = new Hash(h);
             offset += Hash.HASH_LENGTH;
         }
         if (fragmented) {
+            if (offset + 4 >= preprocessed.length)
+                return -1;
             messageId = DataHelper.fromLong(preprocessed, offset, 4);
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("reading messageId " + messageId + " at offset "+ offset 
@@ -241,6 +249,8 @@ public class FragmentHandler {
             offset += extendedSize; // we don't interpret these yet, but skip them for now
         }
         
+        if (offset + 2 >= preprocessed.length)
+            return -1;
         int size = (int)DataHelper.fromLong(preprocessed, offset, 2);
         offset += 2;