diff --git a/router/java/src/net/i2p/router/message/SendMessageDirectJob.java b/router/java/src/net/i2p/router/message/SendMessageDirectJob.java
index d0a7665742dc5425c3c236a07b603d429d8bd50f..8027c4d441b965823fc6996407eafd7b397fc4f9 100644
--- a/router/java/src/net/i2p/router/message/SendMessageDirectJob.java
+++ b/router/java/src/net/i2p/router/message/SendMessageDirectJob.java
@@ -19,6 +19,7 @@ import net.i2p.router.JobImpl;
 import net.i2p.router.MessageSelector;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.ReplyJob;
+import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
 
@@ -75,10 +76,12 @@ public class SendMessageDirectJob extends JobImpl {
                           + " [expiring in " + (_expiration-now) + "]", getAddedBy());
         }
 
-        if (_expiration < now) {
+        if (_expiration < now - Router.CLOCK_FUDGE_FACTOR) {
             if (_log.shouldLog(Log.ERROR))
                 _log.error("Timed out sending message " + _message + " directly (expiration = " 
                            + new Date(_expiration) + ") to " + _targetHash.toBase64(), getAddedBy());
+            if (_onFail != null)
+                getContext().jobQueue().addJob(_onFail);
             return;
         }
         if (_router != null) {
@@ -104,6 +107,8 @@ public class SendMessageDirectJob extends JobImpl {
                         _log.error("Unable to find the router to send to: " + _targetHash 
                                    + " after searching for " + (getContext().clock().now()-_searchOn) 
                                    + "ms, message: " + _message, getAddedBy());
+                    if (_onFail != null)
+                        getContext().jobQueue().addJob(_onFail);
                 }
             }
         }
diff --git a/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java b/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java
index 104298acb790b0ef4ddd560d07ecac664bb1b247..78a2d32524bcc67446e8b16c797ac906f3403efc 100644
--- a/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java
+++ b/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java
@@ -32,6 +32,7 @@ import net.i2p.router.MessageReceptionInfo;
 import net.i2p.router.MessageSelector;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.ReplyJob;
+import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.router.TunnelInfo;
 import net.i2p.util.Log;
@@ -97,6 +98,8 @@ public class SendTunnelMessageJob extends JobImpl {
                 if (_log.shouldLog(Log.ERROR))
                     _log.error("Someone br0ke us.  where is this message supposed to go again?", 
                                getAddedBy());
+                if (_onFailure != null)
+                    getContext().jobQueue().addJob(_onFailure);
                 return;
             } else {
                 forwardToGateway();
@@ -145,9 +148,13 @@ public class SendTunnelMessageJob extends JobImpl {
         } catch (IOException ioe) {
             if (_log.shouldLog(Log.ERROR))
                 _log.error("Error writing out the tunnel message to send to the tunnel", ioe);
+            if (_onFailure != null)
+                getContext().jobQueue().addJob(_onFailure);
         } catch (DataFormatException dfe) {
             if (_log.shouldLog(Log.ERROR))
                 _log.error("Error writing out the tunnel message to send to the tunnel", dfe);
+            if (_onFailure != null)
+                getContext().jobQueue().addJob(_onFailure);
         }
         return;
     }
@@ -179,7 +186,7 @@ public class SendTunnelMessageJob extends JobImpl {
                 _log.debug("Tunnel message created: " + msg + " out of encrypted message: " 
                            + _message);
             long now = getContext().clock().now();
-            if (_expiration < now) {
+            if (_expiration < now - Router.CLOCK_FUDGE_FACTOR) {
                 if (_log.shouldLog(Log.ERROR))
                     _log.error("We are the gateway to " + info.getTunnelId().getTunnelId() 
                                + " and the message " + msg.getUniqueId() + " is valid, but it has timed out (" 
@@ -468,7 +475,7 @@ public class SendTunnelMessageJob extends JobImpl {
             if (_log.shouldLog(Log.WARN))
                 _log.warn("Why are we trying to send a " + _message.getClass().getName() 
                            + " message with " + (_expiration-now) + "ms left?", getAddedBy());
-            if (timeLeft < 0) {
+            if (timeLeft + Router.CLOCK_FUDGE_FACTOR < 0) {
                 _log.error("Timed out honoring request to send a " + _message.getClass().getName() 
                            + " message remotely [" + _message.getUniqueId() + "] expired "
                            + (0-timeLeft) + "ms ago");
diff --git a/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java b/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java
index b1f7fd7d217ae135407e89e8a5b210724a29fd33..a1accab048f5aa43f43557fe114fd409a9c56db8 100644
--- a/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java
@@ -444,6 +444,7 @@ public class TCPTransport extends TransportImpl {
                 con.closeConnection();
                 // remove the old ref, since they likely just created a new identity
                 _context.netDb().fail(target.getIdentity().getHash());
+                _context.shitlist().shitlistRouter(target.getIdentity().getHash());
                 return false;
             } else {
                 if (_log.shouldLog(Log.DEBUG))