diff --git a/apps/sam/java/src/net/i2p/sam/MasterSession.java b/apps/sam/java/src/net/i2p/sam/MasterSession.java
index ba64e9255a6f97d88818251a6568e51208b4818f..76ba6ab3a45376e76d844026cfad8aa809b52f51 100644
--- a/apps/sam/java/src/net/i2p/sam/MasterSession.java
+++ b/apps/sam/java/src/net/i2p/sam/MasterSession.java
@@ -42,6 +42,7 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S
 	private final SAMv3DatagramServer dgs;
 	private final Map<String, SAMMessageSess> sessions;
 	private final StreamAcceptor streamAcceptor;
+	private static final String[] INVALID_OPTS = { "PORT", "HOST", "FROM_PORT", "TO_PORT", "PROTOCOL" };
 
 	/**
 	 * Build a Session according to information
@@ -57,6 +58,11 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S
 	public MasterSession(String nick, SAMv3DatagramServer dgServer, SAMv3Handler handler, Properties props) 
 			throws IOException, DataFormatException, SAMException {
 		super(nick);
+		for (int i = 0; i < INVALID_OPTS.length; i++) {
+			String p = INVALID_OPTS[i];
+			if (props.containsKey(p))
+				throw new SAMException("MASTER session options may not contain " + p);
+		}
 		dgs = dgServer;
 		sessions = new ConcurrentHashMap<String, SAMMessageSess>(4);
 		this.handler = handler;
@@ -162,15 +168,13 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S
 
 		rec = new SessionRecord(getDestination().toBase64(), props, subhandler);
 		try {
-			if (!SAMv3Handler.sSessionsHash.put(nick, rec))
-				return "Duplicate ID " + nick;
+			SAMv3Handler.sSessionsHash.putDupDestOK(nick, rec);
 			sessions.put(nick, sess);
 		} catch (SessionsDB.ExistingIdException e) {
-			return e.toString();
-		} catch (SessionsDB.ExistingDestException e) {
-			// fixme need new db method for dup dests
+			return "Duplicate ID " + nick;
 		}
-		// listeners etc
+		if (_log.shouldWarn())
+			_log.warn("added " + style + " proto " + listenProtocol + " port " + listenPort);
 
 		sess.start();
 		// all ok
diff --git a/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java b/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
index a65f387cf18597f4a8b878a3c10a7c5e66d6313b..328749afb4800d23fbf8e65c094a1686fc8001f9 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
@@ -67,11 +67,10 @@ abstract class SAMMessageSession implements SAMMessageSess {
         _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Initializing SAM message-based session");
-
-        handler = new SAMMessageSessionHandler(destStream, props);
-        session = handler.getSession();
         listenProtocol = I2PSession.PROTO_ANY;
         listenPort = I2PSession.PORT_ANY;
+        handler = new SAMMessageSessionHandler(destStream, props);
+        session = handler.getSession();
     }
 
     /**
@@ -89,11 +88,10 @@ abstract class SAMMessageSession implements SAMMessageSess {
         _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Initializing SAM message-based session");
-
-        session = sess;
-        handler = new SAMMessageSessionHandler(session);
         this.listenProtocol = listenProtocol;
         this.listenPort = listenPort;
+        session = sess;
+        handler = new SAMMessageSessionHandler(session);
     }
 
     /*
diff --git a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java
index 42edac0b5890f034012418ae520b4f9cdea6f190..6cebed71da3a312893412730daf63e4a04899ad5 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java
@@ -368,7 +368,7 @@ class SAMStreamSession implements SAMMessageSess {
      *  @since 0.9.25 moved from subclass SAMv3StreamSession to implement SAMMessageSess
      */
     public boolean sendBytes(String s, byte[] b, int pr, int fp, int tp) throws I2PSessionException {
-    	throw new I2PSessionException("Unsupported in stream or master session");
+    	throw new I2PSessionException("Unsupported in STREAM or MASTER session");
     }
 
     /** 
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
index e8284964ff3231ad15ad7d0a3c70c88d32cf89ca..48774d5652ed1183ec6f0edc8a5b94656922a8a7 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
@@ -314,10 +314,13 @@ class SAMv3Handler extends SAMv1Handler
 		} catch (IOException e) {
 			if (_log.shouldLog(Log.DEBUG))
 				_log.debug("Caught IOException in handler", e);
+			writeString(SESSION_ERROR, e.getMessage());
 		} catch (SAMException e) {
 			_log.error("Unexpected exception for message [" + msg + ']', e);
+			writeString(SESSION_ERROR, e.getMessage());
 		} catch (RuntimeException e) {
 			_log.error("Unexpected exception for message [" + msg + ']', e);
+			writeString(SESSION_ERROR, e.getMessage());
 		} finally {
 			if (_log.shouldLog(Log.DEBUG))
 				_log.debug("Stopping handler");
@@ -467,8 +470,6 @@ class SAMv3Handler extends SAMv1Handler
 					// SAMStreamSession constructor.
 					allProps.setProperty("i2p.streaming.enforceProtocol", "true");
 					allProps.setProperty("i2cp.dontPublishLeaseSet", "false");
-					allProps.setProperty("FROM_PORT", Integer.toString(I2PSession.PORT_UNSPECIFIED));
-					allProps.setProperty("TO_PORT", Integer.toString(I2PSession.PORT_UNSPECIFIED));
 				}
 
 				try {
@@ -530,9 +531,9 @@ class SAMv3Handler extends SAMv1Handler
 					msg = msess.remove(nick, props);
 				}
 				if (msg == null)
-					return writeString("SESSION STATUS RESULT=OK", opcode + ' ' + nick);
+					return writeString("SESSION STATUS RESULT=OK ID=\"" + nick + '"', opcode + ' ' + nick);
 				else
-					return writeString(SESSION_ERROR, msg);
+					return writeString(SESSION_ERROR + " ID=\"" + nick + '"', msg);
 			} else {
 				if (_log.shouldLog(Log.DEBUG))
 					_log.debug("Unrecognized SESSION message opcode: \""
@@ -581,10 +582,9 @@ class SAMv3Handler extends SAMv1Handler
 
 		if ( session != null )
 		{
-			_log.error ( "STREAM message received, but this session is a master session" );
-			
+			_log.error("v3 control socket cannot be used for STREAM");
 			try {
-				notifyStreamResult(true, "I2P_ERROR", "master session cannot be used for streams");
+				notifyStreamResult(true, "I2P_ERROR", "v3 control socket cannot be used for STREAM");
 			} catch (IOException e) {}
 			return false;
 		}
diff --git a/apps/sam/java/src/net/i2p/sam/SessionsDB.java b/apps/sam/java/src/net/i2p/sam/SessionsDB.java
index 21876d7cc6992bd26c1fb0500bf11919fd078b3f..dfdc3c0041a143ce5904ce2a1f7e7c224d91c8be 100644
--- a/apps/sam/java/src/net/i2p/sam/SessionsDB.java
+++ b/apps/sam/java/src/net/i2p/sam/SessionsDB.java
@@ -32,8 +32,7 @@ class SessionsDB {
 		map = new HashMap<String, SessionRecord>() ;
 	}
 
-	/** @return success */
-	synchronized public boolean put( String nick, SessionRecord session )
+	public synchronized void put(String nick, SessionRecord session)
 		throws ExistingIdException, ExistingDestException
 	{
 		if ( map.containsKey(nick) ) {
@@ -44,14 +43,19 @@ class SessionsDB {
 				throw new ExistingDestException();
 			}
 		}
+		session.createThreadGroup("SAM session "+nick);
+		map.put(nick, session) ;
+	}
 
-		if ( !map.containsKey(nick) ) {
-			session.createThreadGroup("SAM session "+nick);
-			map.put(nick, session) ;
-			return true ;
+	/** @since 0.9.25 */
+	public synchronized void putDupDestOK(String nick, SessionRecord session)
+		throws ExistingIdException
+	{
+		if (map.containsKey(nick)) {
+			throw new ExistingIdException();
 		}
-		else
-			return false ;
+		session.createThreadGroup("SAM session "+nick);
+		map.put(nick, session) ;
 	}
 
 	/** @return true if removed */
diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMReader.java b/apps/sam/java/src/net/i2p/sam/client/SAMReader.java
index 0ab88cfcee93bc4b1916401632dc88ba5d0dea97..7153998e94d7a21a0734d722ac67cb1571753a7b 100644
--- a/apps/sam/java/src/net/i2p/sam/client/SAMReader.java
+++ b/apps/sam/java/src/net/i2p/sam/client/SAMReader.java
@@ -137,6 +137,10 @@ public class SAMReader {
                     if ( (eq > 0) && (eq < pair.length() - 1) ) {
                         String name = pair.substring(0, eq);
                         String val = pair.substring(eq+1);
+                        if (val.length() <= 0) {
+                            _log.error("Empty value for " + name);
+                            continue;
+                        }
                         while ( (val.charAt(0) == '\"') && (val.length() > 0) )
                             val = val.substring(1);
                         while ( (val.length() > 0) && (val.charAt(val.length()-1) == '\"') )
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 a0d5d15607de7ed691844f992494612370276f1e..4314965414d8462509910d809ff3bfe985d49702 100644
--- a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
+++ b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
@@ -702,8 +702,7 @@ public class SAMStreamSink {
                 samOut.flush();
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("SESSION " + command + " sent");
-                if (mode == STREAM) {
-                    // why only waiting in stream mode?
+                //if (mode == STREAM) {
                     boolean ok;
                     if (masterMode)
                         ok = eventHandler.waitForSessionAddReply();
@@ -713,6 +712,22 @@ public class SAMStreamSink {
                         throw new IOException("SESSION " + command + " failed");
                     if (_log.shouldLog(Log.DEBUG))
                         _log.debug("SESSION " + command + " reply found: " + ok);
+                //}
+                if (masterMode) {
+                    // do a bunch more
+                    req = "SESSION ADD STYLE=STREAM FROM_PORT=99 ID=stream99\n";
+                    samOut.write(req.getBytes("UTF-8"));
+                    req = "SESSION ADD STYLE=STREAM FROM_PORT=98 ID=stream98\n";
+                    samOut.write(req.getBytes("UTF-8"));
+                    req = "SESSION ADD STYLE=DATAGRAM PORT=9997 LISTEN_PORT=97 ID=dg97\n";
+                    samOut.write(req.getBytes("UTF-8"));
+                    req = "SESSION ADD STYLE=DATAGRAM PORT=9996 FROM_PORT=96 ID=dg96\n";
+                    samOut.write(req.getBytes("UTF-8"));
+                    req = "SESSION ADD STYLE=RAW PORT=9995 LISTEN_PORT=95 ID=raw95\n";
+                    samOut.write(req.getBytes("UTF-8"));
+                    req = "SESSION ADD STYLE=RAW PORT=9994 FROM_PORT=94 LISTEN_PROTOCOL=222 ID=raw94\n";
+                    samOut.write(req.getBytes("UTF-8"));
+                    samOut.flush();
                 }
                 req = "NAMING LOOKUP NAME=ME\n";
                 samOut.write(req.getBytes("UTF-8"));