From fadc624f7c3f16c61a91664a22e33190ad2c567b Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Tue, 31 Mar 2015 13:18:11 +0000
Subject: [PATCH] API: Fix some client-side APIs to honor defaults in
 Properties; add javadocs to specify where we do and don't (ticket #1491)

---
 .../java/src/net/i2p/i2ptunnel/I2PTunnel.java |  2 +
 .../net/i2p/i2ptunnel/TunnelController.java   |  4 ++
 .../client/streaming/I2PSocketManager.java    |  3 +
 .../streaming/I2PSocketManagerFactory.java    | 11 +++-
 .../streaming/impl/ConnectionOptions.java     | 55 ++++++++++---------
 .../streaming/impl/I2PSocketManagerFull.java  |  4 ++
 .../streaming/impl/I2PSocketOptionsImpl.java  | 17 ++++--
 core/java/src/net/i2p/client/I2PClient.java   |  2 +
 .../src/net/i2p/client/I2PSessionImpl.java    | 15 +++--
 core/java/src/net/i2p/data/DataHelper.java    | 18 +++++-
 .../src/net/i2p/data/i2cp/GetDateMessage.java |  4 ++
 .../src/net/i2p/data/i2cp/SessionConfig.java  |  4 ++
 .../net/i2p/router/TunnelPoolSettings.java    |  5 +-
 .../client/ClientMessageEventListener.java    | 11 ++++
 14 files changed, 116 insertions(+), 39 deletions(-)

diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index af4ef1d95a..6fc491e394 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -540,6 +540,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
      * This DOES update a running TunnelTask, but NOT the session.
      * A more efficient runClientOptions().
      *
+     * Defaults in opts properties are not recommended, they may or may not be honored.
+     *
      * @param opts non-null
      * @since 0.9.1
      */
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 6c46c99a6b..179b54ae71 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -113,6 +113,8 @@ public class TunnelController implements Logging {
      * the prefix should be used (and, in turn, that prefix should be stripped off
      * before being interpreted by this controller)
      * 
+     * Defaults in config properties are not recommended, they may or may not be honored.
+     * 
      * @param config original key=value mapping non-null
      * @param prefix beginning of key values that are relevant to this tunnel
      */
@@ -121,6 +123,7 @@ public class TunnelController implements Logging {
     }
 
     /**
+     * Defaults in config properties are not recommended, they may or may not be honored.
      * 
      * @param config original key=value mapping non-null
      * @param prefix beginning of key values that are relevant to this tunnel
@@ -506,6 +509,7 @@ public class TunnelController implements Logging {
     
     /**
      *  These are the ones stored with a prefix of "option."
+     *  Defaults in config properties are not honored.
      *
      *  @return keys with the "option." prefix stripped, non-null
      *  @since 0.9.1 Much better than getClientOptions()
diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java
index b7a5732d00..5d1819b702 100644
--- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java
+++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java
@@ -73,6 +73,9 @@ public interface I2PSocketManager {
 
     /**
      *  Create a modified copy of the current options, to be used in a setDefaultOptions() call.
+     *
+     *  As of 0.9.19, defaults in opts are honored.
+     *
      *  @param opts The new options, may be null
      */
     public I2PSocketOptions buildOptions(Properties opts);
diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java
index 0f5be9cad6..00c04d83b3 100644
--- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java
+++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java
@@ -49,6 +49,7 @@ public class I2PSocketManagerFactory {
      * I2CP router on the local machine on the default port (7654).
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      * 
      * @return the newly created socket manager, or null if there were errors
      */
@@ -61,6 +62,7 @@ public class I2PSocketManagerFactory {
      * I2CP router on the local machine on the default port (7654).
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      * 
      * @param opts Streaming and I2CP options, may be null
      * @return the newly created socket manager, or null if there were errors
@@ -74,6 +76,7 @@ public class I2PSocketManagerFactory {
      * I2CP router on the specified host and port.
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      * 
      * @param host I2CP host null to use default, ignored if in router context
      * @param port I2CP port <= 0 to use default, ignored if in router context
@@ -88,6 +91,7 @@ public class I2PSocketManagerFactory {
      * I2CP router on the given machine reachable through the given port.
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      *
      * @param i2cpHost I2CP host null to use default, ignored if in router context
      * @param i2cpPort I2CP port <= 0 to use default, ignored if in router context
@@ -115,6 +119,7 @@ public class I2PSocketManagerFactory {
      * stream and connected to the default I2CP host and port.
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      *
      * @param myPrivateKeyStream private key stream, format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
      *                           or null for a transient destination. Caller must close.
@@ -129,6 +134,7 @@ public class I2PSocketManagerFactory {
      * stream and connected to the default I2CP host and port.
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      *
      * @param myPrivateKeyStream private key stream, format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
      *                           or null for a transient destination. Caller must close.
@@ -145,6 +151,7 @@ public class I2PSocketManagerFactory {
      * port.
      * 
      * Blocks for a long time while the router builds tunnels.
+     * The nonblocking createDisconnectedManager() is preferred.
      *
      * @param myPrivateKeyStream private key stream, format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
      *                           or null for a transient destination. Caller must close.
@@ -220,11 +227,11 @@ public class I2PSocketManagerFactory {
         Properties syscopy = (Properties) System.getProperties().clone();
         for (Map.Entry<Object, Object> e : syscopy.entrySet()) {
             String name = (String) e.getKey();
-            if (!opts.containsKey(name))
+            if (opts.getProperty(name) != null)
                 opts.setProperty(name, (String) e.getValue());
         }
         // as of 0.8.1 (I2CP default is BestEffort)
-        if (!opts.containsKey(I2PClient.PROP_RELIABILITY))
+        if (opts.getProperty(I2PClient.PROP_RELIABILITY) == null)
             opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE);
 
         if (i2cpHost != null)
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionOptions.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionOptions.java
index fe4c5d0c3f..51e8b5312c 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionOptions.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/ConnectionOptions.java
@@ -264,6 +264,9 @@ class ConnectionOptions extends I2PSocketOptionsImpl {
     /**
      *  Sets max buffer size, connect timeout, read timeout, and write timeout
      *  from properties. Does not set local port or remote port.
+     *
+     *  As of 0.9.19, defaults in opts are honored.
+     *
      *  @param opts may be null
      */
     public ConnectionOptions(Properties opts) {
@@ -388,66 +391,68 @@ class ConnectionOptions extends I2PSocketOptionsImpl {
     
     /**
      *  Note: NOT part of the interface
+     *
+     *  As of 0.9.19, defaults in opts are honored.
      */
     @Override
     public void setProperties(Properties opts) {
         super.setProperties(opts);
         if (opts == null) return;
-        if (opts.containsKey(PROP_MAX_WINDOW_SIZE))
+        if (opts.getProperty(PROP_MAX_WINDOW_SIZE) != null)
             setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
-        if (opts.containsKey(PROP_CONNECT_DELAY))
+        if (opts.getProperty(PROP_CONNECT_DELAY) != null)
             setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
-        if (opts.containsKey(PROP_PROFILE))
+        if (opts.getProperty(PROP_PROFILE) != null)
             setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
-        if (opts.containsKey(PROP_MAX_MESSAGE_SIZE))
+        if (opts.getProperty(PROP_MAX_MESSAGE_SIZE) != null)
             setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, Packet.MAX_PAYLOAD_SIZE));
-        if (opts.containsKey(PROP_INITIAL_RECEIVE_WINDOW))
+        if (opts.getProperty(PROP_INITIAL_RECEIVE_WINDOW) != null)
             setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
-        if (opts.containsKey(PROP_INITIAL_RESEND_DELAY))
+        if (opts.getProperty(PROP_INITIAL_RESEND_DELAY) != null)
             setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000));
-        if (opts.containsKey(PROP_INITIAL_ACK_DELAY))
+        if (opts.getProperty(PROP_INITIAL_ACK_DELAY) != null)
             setSendAckDelay(getInt(opts, PROP_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY));
-        if (opts.containsKey(PROP_INITIAL_WINDOW_SIZE))
+        if (opts.getProperty(PROP_INITIAL_WINDOW_SIZE) != null)
             setWindowSize(getInt(opts, PROP_INITIAL_WINDOW_SIZE, INITIAL_WINDOW_SIZE));
-        if (opts.containsKey(PROP_MAX_RESENDS))
+        if (opts.getProperty(PROP_MAX_RESENDS) != null)
             setMaxResends(getInt(opts, PROP_MAX_RESENDS, DEFAULT_MAX_SENDS));
         // handled in super()
-        //if (opts.containsKey(PROP_WRITE_TIMEOUT))
+        //if (opts.getProperty(PROP_WRITE_TIMEOUT))
         //    setWriteTimeout(getInt(opts, PROP_WRITE_TIMEOUT, -1));
-        if (opts.containsKey(PROP_INACTIVITY_TIMEOUT))
+        if (opts.getProperty(PROP_INACTIVITY_TIMEOUT) != null)
             setInactivityTimeout(getInt(opts, PROP_INACTIVITY_TIMEOUT, DEFAULT_INACTIVITY_TIMEOUT));
-        if (opts.containsKey(PROP_INACTIVITY_ACTION))
+        if (opts.getProperty(PROP_INACTIVITY_ACTION) != null)
             setInactivityAction(getInt(opts, PROP_INACTIVITY_ACTION, DEFAULT_INACTIVITY_ACTION));
         setInboundBufferSize(getMaxMessageSize() * (Connection.MAX_WINDOW_SIZE + 2));
-        if (opts.contains(PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR))
+        if (opts.getProperty(PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR) != null)
             setCongestionAvoidanceGrowthRateFactor(getInt(opts, PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR,
                                                           DEFAULT_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR));
-        if (opts.contains(PROP_SLOW_START_GROWTH_RATE_FACTOR))
+        if (opts.getProperty(PROP_SLOW_START_GROWTH_RATE_FACTOR) != null)
             setSlowStartGrowthRateFactor(getInt(opts, PROP_SLOW_START_GROWTH_RATE_FACTOR,
                                                 DEFAULT_SLOW_START_GROWTH_RATE_FACTOR));
-        if (opts.containsKey(PROP_CONNECT_TIMEOUT))
+        if (opts.getProperty(PROP_CONNECT_TIMEOUT) != null)
             // overrides default in super()
             setConnectTimeout(getInt(opts, PROP_CONNECT_TIMEOUT, Connection.DEFAULT_CONNECT_TIMEOUT));
-        if (opts.containsKey(PROP_ANSWER_PINGS))
+        if (opts.getProperty(PROP_ANSWER_PINGS) != null)
             setAnswerPings(getBool(opts, PROP_ANSWER_PINGS, DEFAULT_ANSWER_PINGS));
-        if (opts.containsKey(PROP_ENFORCE_PROTO))
+        if (opts.getProperty(PROP_ENFORCE_PROTO) != null)
             setEnforceProtocol(getBool(opts, PROP_ENFORCE_PROTO, DEFAULT_ENFORCE_PROTO));
-        if (opts.containsKey(PROP_DISABLE_REJ_LOG))
+        if (opts.getProperty(PROP_DISABLE_REJ_LOG) != null)
             setDisableRejectLogging(getBool(opts, PROP_DISABLE_REJ_LOG, false));
         initLists(opts);
-        if (opts.containsKey(PROP_MAX_CONNS_MIN))
+        if (opts.getProperty(PROP_MAX_CONNS_MIN) != null)
             _maxConnsPerMinute = getInt(opts, PROP_MAX_CONNS_MIN, 0);
-        if (opts.containsKey(PROP_MAX_CONNS_HOUR))
+        if (opts.getProperty(PROP_MAX_CONNS_HOUR) != null)
             _maxConnsPerHour = getInt(opts, PROP_MAX_CONNS_HOUR, 0);
-        if (opts.containsKey(PROP_MAX_CONNS_DAY))
+        if (opts.getProperty(PROP_MAX_CONNS_DAY) != null)
             _maxConnsPerDay = getInt(opts, PROP_MAX_CONNS_DAY, 0);
-        if (opts.containsKey(PROP_MAX_TOTAL_CONNS_MIN))
+        if (opts.getProperty(PROP_MAX_TOTAL_CONNS_MIN) != null)
             _maxTotalConnsPerMinute = getInt(opts, PROP_MAX_TOTAL_CONNS_MIN, 0);
-        if (opts.containsKey(PROP_MAX_TOTAL_CONNS_HOUR))
+        if (opts.getProperty(PROP_MAX_TOTAL_CONNS_HOUR) != null)
             _maxTotalConnsPerHour = getInt(opts, PROP_MAX_TOTAL_CONNS_HOUR, 0);
-        if (opts.containsKey(PROP_MAX_TOTAL_CONNS_DAY))
+        if (opts.getProperty(PROP_MAX_TOTAL_CONNS_DAY) != null)
             _maxTotalConnsPerDay = getInt(opts, PROP_MAX_TOTAL_CONNS_DAY, 0);
-        if (opts.containsKey(PROP_MAX_STREAMS))
+        if (opts.getProperty(PROP_MAX_STREAMS) != null)
             _maxConns = getInt(opts, PROP_MAX_STREAMS, 0);
         
         _rto = getInt(opts, PROP_INITIAL_RTO, INITIAL_RTO);
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java
index 41396edb86..630b1f0b6a 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java
@@ -102,6 +102,9 @@ public class I2PSocketManagerFull implements I2PSocketManager {
 
     /**
      *  Create a modified copy of the current options, to be used in a setDefaultOptions() call.
+     *
+     *  As of 0.9.19, defaults in opts are honored.
+     *
      *  @param opts The new options, may be null
      */
     public I2PSocketOptions buildOptions(Properties opts) {
@@ -216,6 +219,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
      *  Parameters in the I2PSocketOptions interface may be changed directly
      *  with the setters; no need to use this method for those.
      *  This does NOT update the underlying I2CP or tunnel options; use getSession().updateOptions() for that.
+     *
      *  @param options as created from a call to buildOptions(properties), non-null
      */
     public void setDefaultOptions(I2PSocketOptions options) {
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketOptionsImpl.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketOptionsImpl.java
index 0c077cccd9..5516451a05 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketOptionsImpl.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketOptionsImpl.java
@@ -47,6 +47,9 @@ class I2PSocketOptionsImpl implements I2PSocketOptions {
     /**
      *  Sets max buffer size, connect timeout, read timeout, and write timeout
      *  from properties. Does not set local port or remote port.
+     *
+     *  As of 0.9.19, defaults in opts are honored.
+     *
      *  @param opts may be null
      */
     public I2PSocketOptionsImpl(Properties opts) {
@@ -56,17 +59,20 @@ class I2PSocketOptionsImpl implements I2PSocketOptions {
     /**
      *  Sets max buffer size, connect timeout, read timeout, and write timeout
      *  from properties. Does not set local port or remote port.
+     *
+     *  As of 0.9.19, defaults in opts are honored.
+     *
      *  @param opts may be null
      */
     public void setProperties(Properties opts) {
         if (opts == null) return;
-        if (opts.containsKey(PROP_BUFFER_SIZE))
+        if (opts.getProperty(PROP_BUFFER_SIZE) != null)
             _maxBufferSize = getInt(opts, PROP_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
-        if (opts.containsKey(PROP_CONNECT_TIMEOUT))
+        if (opts.getProperty(PROP_CONNECT_TIMEOUT) != null)
             _connectTimeout = getInt(opts, PROP_CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT);
-        if (opts.containsKey(PROP_READ_TIMEOUT))
+        if (opts.getProperty(PROP_READ_TIMEOUT) != null)
             _readTimeout = getInt(opts, PROP_READ_TIMEOUT, -1);
-        if (opts.containsKey(PROP_WRITE_TIMEOUT))
+        if (opts.getProperty(PROP_WRITE_TIMEOUT) != null)
             _writeTimeout = getInt(opts, PROP_WRITE_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
     }
     
@@ -95,6 +101,9 @@ class I2PSocketOptionsImpl implements I2PSocketOptions {
         }
     }
     
+    /**
+     *  Not part of the API, not for external use.
+     */
     public static double getDouble(Properties opts, String name, double defaultVal) {
         if (opts == null) return defaultVal;
         String val = opts.getProperty(name);
diff --git a/core/java/src/net/i2p/client/I2PClient.java b/core/java/src/net/i2p/client/I2PClient.java
index c4503608cf..273ba7e2d9 100644
--- a/core/java/src/net/i2p/client/I2PClient.java
+++ b/core/java/src/net/i2p/client/I2PClient.java
@@ -72,6 +72,8 @@ public interface I2PClient {
      * the router how to handle the new session, and to configure the end to end
      * encryption.
      *
+     * As of 0.9.19, defaults in options are honored.
+     *
      * @param destKeyStream location from which to read the Destination, PrivateKey, and SigningPrivateKey from,
      *                      format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
      * @param options set of options to configure the router with, if null will use System properties
diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java
index 7fd1759785..0c89835282 100644
--- a/core/java/src/net/i2p/client/I2PSessionImpl.java
+++ b/core/java/src/net/i2p/client/I2PSessionImpl.java
@@ -235,6 +235,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
      * Create a new session, reading the Destination, PrivateKey, and SigningPrivateKey
      * from the destKeyStream, and using the specified options to connect to the router
      *
+     * As of 0.9.19, defaults in options are honored.
+     *
      * @param destKeyStream stream containing the private key data,
      *                             format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
      * @param options set of options to configure the router with, if null will use System properties
@@ -314,11 +316,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
         }
     }
 
-    /** save some memory, don't pass along the pointless properties */
+    /**
+     *  Save some memory, don't pass along the pointless properties.
+     *  As of 0.9.19, defaults from options will be promoted to real values in rv.
+     *  @return a new Properties without defaults
+     */
     private Properties filter(Properties options) {
         Properties rv = new Properties();
-        for (Object oKey : options.keySet()) { // TODO-Java6: s/keySet()/stringPropertyNames()/
-            String key = (String) oKey;
+        for (String key : options.stringPropertyNames()) {
             if (key.startsWith("java.") ||
                 key.startsWith("user.") ||
                 key.startsWith("os.") ||
@@ -787,7 +792,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
     I2CPMessageProducer getProducer() { return _producer; }
 
     /**
-     * Retrieve the configuration options
+     * Retrieve the configuration options, filtered.
+     * All defaults passed in via constructor have been promoted to the primary map.
+     *
      * @return non-null, if insantiated with null options, this will be the System properties.
      */
     Properties getOptions() { return _options; }
diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java
index 17a4ff42aa..ffa1d2577d 100644
--- a/core/java/src/net/i2p/data/DataHelper.java
+++ b/core/java/src/net/i2p/data/DataHelper.java
@@ -172,11 +172,13 @@ public class DataHelper {
      * Property keys and values must not contain '=' or ';', this is not checked and they are not escaped
      * Keys and values must be 255 bytes or less,
      * Formatted length must not exceed 65535 bytes
-     * @throws DataFormatException if either is too long.
+     *
+     * Properties from the defaults table of props (if any) are not written out by this method.
      *
      * @param rawStream stream to write to
      * @param props properties to write out
-     * @throws DataFormatException if there is not enough valid data to write out
+     * @throws DataFormatException if there is not enough valid data to write out,
+     *                             or a length limit is exceeded
      * @throws IOException if there is an IO error writing out the data
      */
     public static void writeProperties(OutputStream rawStream, Properties props) 
@@ -190,7 +192,8 @@ public class DataHelper {
      * Property keys and values must not contain '=' or ';', this is not checked and they are not escaped
      * Keys and values must be 255 bytes or less,
      * Formatted length must not exceed 65535 bytes
-     * @throws DataFormatException if either is too long.
+     *
+     * Properties from the defaults table of props (if any) are not written out by this method.
      *
      * jrandom disabled UTF-8 in mid-2004, for performance reasons,
      * i.e. slow foo.getBytes("UTF-8")
@@ -199,6 +202,7 @@ public class DataHelper {
      * Use utf8 = false for RouterAddress (fast, non UTF-8)
      * Use utf8 = true for SessionConfig (slow, UTF-8)
      * @param props source may be null
+     * @throws DataFormatException if a length limit is exceeded
      */
     public static void writeProperties(OutputStream rawStream, Properties props, boolean utf8) 
             throws DataFormatException, IOException {
@@ -213,6 +217,8 @@ public class DataHelper {
      * Keys and values must be 255 bytes or less,
      * Formatted length must not exceed 65535 bytes
      *
+     * Properties from the defaults table of props (if any) are not written out by this method.
+     *
      * jrandom disabled UTF-8 in mid-2004, for performance reasons,
      * i.e. slow foo.getBytes("UTF-8")
      * Re-enable it so we can pass UTF-8 tunnel names through the I2CP SessionConfig.
@@ -269,6 +275,8 @@ public class DataHelper {
      * Strings will be UTF-8 encoded in the byte array.
      * Warning - confusing method name, Properties is the source.
      *
+     * Properties from the defaults table of props (if any) are not written out by this method.
+     *
      * @deprecated unused
      *
      * @param target returned array as specified in data structure spec
@@ -364,6 +372,8 @@ public class DataHelper {
      * Formatted length must not exceed 65535 bytes
      * Warning - confusing method name, Properties is the source.
      *
+     * Properties from the defaults table of props (if any) are not written out by this method.
+     *
      * @throws DataFormatException if key, value, or total is too long
      */
     public static byte[] toProperties(Properties opts) throws DataFormatException {
@@ -477,6 +487,8 @@ public class DataHelper {
      * Note that this does not escape the \r or \n that are unescaped in loadProps() above.
      * As of 0.8.1, file will be mode 600.
      *
+     * Properties from the defaults table of props (if any) are not written out by this method.
+     *
      * Leading or trailing whitespace in values is not checked but
      * will be trimmed by loadProps()
      *
diff --git a/core/java/src/net/i2p/data/i2cp/GetDateMessage.java b/core/java/src/net/i2p/data/i2cp/GetDateMessage.java
index 00c5a75b87..a65d626b65 100644
--- a/core/java/src/net/i2p/data/i2cp/GetDateMessage.java
+++ b/core/java/src/net/i2p/data/i2cp/GetDateMessage.java
@@ -45,6 +45,10 @@ public class GetDateMessage extends I2CPMessageImpl {
     }
 
     /**
+     *  Defaults in GetDateMessage options are, in general, NOT honored.
+     *  Defaults are not serialized out-of-JVM, and the router does not recognize defaults in-JVM.
+     *  Client side must promote defaults to the primary map.
+     *
      *  @param version the client's version String to be sent to the router; may be null;
      *                 must be non-null if options is non-null and non-empty.
      *  @param options Client options to be sent to the router; primarily for authentication; may be null;
diff --git a/core/java/src/net/i2p/data/i2cp/SessionConfig.java b/core/java/src/net/i2p/data/i2cp/SessionConfig.java
index e3f8468c70..c4af88db90 100644
--- a/core/java/src/net/i2p/data/i2cp/SessionConfig.java
+++ b/core/java/src/net/i2p/data/i2cp/SessionConfig.java
@@ -91,6 +91,10 @@ public class SessionConfig extends DataStructureImpl {
      * Configure the session with the given options;
      * keys and values 255 bytes (not chars) max each
      *
+     * Defaults in SessionConfig options are, in general, NOT honored.
+     * Defaults are not serialized out-of-JVM, and the router does not recognize defaults in-JVM.
+     * Client side must promote defaults to the primary map.
+     *
      * @param options Properties for this session
      */
     public void setOptions(Properties options) {
diff --git a/router/java/src/net/i2p/router/TunnelPoolSettings.java b/router/java/src/net/i2p/router/TunnelPoolSettings.java
index fd718e4799..329cf5eaed 100644
--- a/router/java/src/net/i2p/router/TunnelPoolSettings.java
+++ b/router/java/src/net/i2p/router/TunnelPoolSettings.java
@@ -237,9 +237,12 @@ public class TunnelPoolSettings {
     public Properties getUnknownOptions() { return _unknownOptions; }
     
     /**
+     *  Defaults in props are NOT honored.
+     *  In-JVM client side must promote defaults to the primary map.
+     *
      *  @param prefix non-null
      */
-    public void readFromProperties(String prefix, Map<Object, Object> props) {
+    public void readFromProperties(String prefix, Properties props) {
         for (Map.Entry<Object, Object> e : props.entrySet()) {
             String name = (String) e.getKey();
             String value = (String) e.getValue();
diff --git a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java
index f8d446079a..0fd8bddcae 100644
--- a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java
+++ b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java
@@ -161,6 +161,11 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
         _runner.disconnected();
     }
     
+    /**
+     *  Defaults in GetDateMessage options are NOT honored.
+     *  Defaults are not serialized out-of-JVM, and the router does not recognize defaults in-JVM.
+     *  Client side must promote defaults to the primary map.
+     */
     private void handleGetDate(GetDateMessage message) {
         // sent by clients >= 0.8.7
         String clientVersion = message.getVersion();
@@ -192,6 +197,9 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
      * sending the DisconnectMessage... but right now the client will send _us_ a
      * DisconnectMessage in return, and not wait around for our DisconnectMessage.
      * So keep it simple.
+     *
+     * Defaults in SessionConfig options are, in general, NOT honored.
+     * In-JVM client side must promote defaults to the primary map.
      */
     private void handleCreateSession(CreateSessionMessage message) {
         SessionConfig in = message.getSessionConfig();
@@ -459,6 +467,9 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
      *
      * Note that this does NOT update the few options handled in
      * ClientConnectionRunner.sessionEstablished(). Those can't be changed later.
+     *
+     * Defaults in SessionConfig options are, in general, NOT honored.
+     * In-JVM client side must promote defaults to the primary map.
      */
     private void handleReconfigureSession(ReconfigureSessionMessage message) {
         SessionConfig cfg = _runner.getConfig();
-- 
GitLab