diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandler.java b/apps/sam/java/src/net/i2p/sam/SAMHandler.java
index 3a1f4aaa7c18d060610913dfeb9d3ff8052ef9f0..e2bcb84fb709d4ad2d3005fa0a9c57c02f5d3df9 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMHandler.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMHandler.java
@@ -102,7 +102,10 @@ abstract class SAMHandler implements Runnable, Handler {
         }
     }
     
-    static public void writeBytes(ByteBuffer data, SocketChannel out) throws IOException {
+    /**
+     *  Caller must synch
+     */
+    private static void writeBytes(ByteBuffer data, SocketChannel out) throws IOException {
         while (data.hasRemaining()) out.write(data);           
         out.socket().getOutputStream().flush();
     }
@@ -132,7 +135,10 @@ abstract class SAMHandler implements Runnable, Handler {
         }
     }
 
-    /** @return success */
+    /**
+     * Unsynchronized, use with caution
+     * @return success
+     */
     public static boolean writeString(String str, SocketChannel out)
     {
     	try {
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
index ff17f07b801bf831ccb894d63eed09f5cc4d1e39..9cc4a500c752a710125ec09d1db5d3ab601e3fed 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
@@ -315,7 +315,7 @@ class SAMv3Handler extends SAMv1Handler
 							} else if (_lastPing < 0) {
 								if (_log.shouldWarn())
 									_log.warn("2nd timeout");
-								writeString("XXX STATUS RESULT=I2P_ERROR MESSAGE=\"command timeout, bye\"\n");
+								writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"command timeout, bye\"\n");
 								break;
 							} else {
 								// don't clear buffer, don't send ping,
diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
index fedd4699814626e771c5b2cd590ded34cc2cdbc9..b582fa8069fa9bdcfbd2017d1314e8150a26f5db 100644
--- a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
+++ b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
@@ -15,6 +15,7 @@ import gnu.getopt.Getopt;
 import net.i2p.I2PAppContext;
 import net.i2p.data.Base32;
 import net.i2p.data.DataHelper;
+import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
 import net.i2p.util.VersionComparator;
 
@@ -35,6 +36,7 @@ public class SAMStreamSink {
     private String _conOptions;
     private SAMReader _reader, _reader2;
     private boolean _isV3;
+    private boolean _isV32;
     private String _v3ID;
     //private boolean _dead;
     /** Connection id (Integer) to peer (Flooder) */
@@ -127,6 +129,11 @@ public class SAMStreamSink {
                 throw new IOException("handshake failed");
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Handshake complete.  we are " + ourDest);
+            if (_isV32) {
+                _log.debug("Starting pinger");
+                Thread t = new Pinger(out);
+                t.start();
+            }
             if (_isV3 && mode != V1DG && mode != V1RAW) {
                 Socket sock2 = connect(isSSL);
                 out = sock2.getOutputStream();
@@ -146,6 +153,32 @@ public class SAMStreamSink {
             _log.error("Unable to connect to SAM at " + _samHost + ":" + _samPort, e);
         }
     }
+
+    private static class Pinger extends I2PAppThread {
+        private final OutputStream _out;
+
+        public Pinger(OutputStream out) {
+            super("SAM Sink Pinger");
+            setDaemon(true);
+            _out = out;
+        }
+
+        public void run() {
+            while (true) {
+                try {
+                    Thread.sleep(127*1000);
+                    synchronized(_out) {
+                        _out.write(DataHelper.getASCII("PING " + System.currentTimeMillis() + '\n'));
+                        _out.flush();
+                    }
+                } catch (InterruptedException ie) {
+                    break;
+                } catch (IOException ioe) {
+                    break;
+                }
+            }
+        }
+    }
     
     private class SinkEventHandler extends SAMEventHandler {
 
@@ -353,6 +386,7 @@ public class SAMStreamSink {
                 _isV3 = VersionComparator.comp(hisVersion, "3") >= 0;
                 String dest;
                 if (_isV3) {
+                    _isV32 = VersionComparator.comp(hisVersion, "3.2") >= 0;
                     // we use the filename as the name in sam.keys
                     // and read it in ourselves
                     File keys = new File("sam.keys");