From e60baaef11af6bcd6e7aee73b9e304732bf9a16e Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Fri, 23 May 2014 15:13:23 +0000
Subject: [PATCH] Backport fix for OPENDJ-1466: Improve initialization of InetSocketAddress in SDK to prevent cached DNS data.

---
 opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java |   85 +++++++++++++++++++---------
 opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java |   51 ++++++++++++++--
 opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java     |    8 ++
 3 files changed, 107 insertions(+), 37 deletions(-)

diff --git a/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java b/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
index 2f397d2..56a5a99 100644
--- a/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
+++ b/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
@@ -211,8 +211,8 @@
                 return timeoutEndTime - currentTime;
             } else {
                 future.handleErrorResult(newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR,
-                        LDAP_CONNECTION_CONNECT_TIMEOUT.get(socketAddress.toString(), getTimeout())
-                                .toString()));
+                        LDAP_CONNECTION_CONNECT_TIMEOUT.get(getSocketAddress().toString(),
+                                getTimeout()).toString()));
                 return 0;
             }
         }
@@ -227,6 +227,8 @@
     private final FilterChain defaultFilterChain;
     private final LDAPOptions options;
     private final InetSocketAddress socketAddress;
+    private final String host;
+    private final int port;
 
     /**
      * Prevents the transport and timeoutChecker being released when there are
@@ -246,8 +248,8 @@
 
     /**
      * Creates a new LDAP connection factory implementation which can be used to
-     * create connections to the Directory Server at the provided host and port
-     * address using provided connection options.
+     * create connections to the Directory Server at the provided address using
+     * provided connection options.
      *
      * @param address
      *            The address of the Directory Server to connect to.
@@ -257,6 +259,8 @@
     public LDAPConnectionFactoryImpl(final InetSocketAddress address, final LDAPOptions options) {
         this.transport = DEFAULT_TRANSPORT.acquireIfNull(options.getTCPNIOTransport());
         this.socketAddress = address;
+        this.host = null;
+        this.port = -1;
         this.options = new LDAPOptions(options);
         this.clientFilter =
                 new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0);
@@ -264,6 +268,30 @@
                 FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build();
     }
 
+    /**
+     * Creates a new LDAP connection factory implementation which can be used to
+     * create connections to the Directory Server at the provided host and port
+     * number using provided connection options.
+     *
+     * @param host
+     *            The host name of the Directory Server to connect to.
+     * @param port
+     *            The port number of the Directory Server to connect to.
+     * @param options
+     *            The LDAP connection options to use when creating connections.
+     */
+    public LDAPConnectionFactoryImpl(final String host, final int port, final LDAPOptions options) {
+        this.transport = DEFAULT_TRANSPORT.acquireIfNull(options.getTCPNIOTransport());
+        this.socketAddress = null;
+        this.host = host;
+        this.port = port;
+        this.options = new LDAPOptions(options);
+        this.clientFilter =
+              new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0);
+        this.defaultFilterChain =
+              FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build();
+    }
+
     @Override
     public void close() {
         if (isClosed.compareAndSet(false, true)) {
@@ -289,7 +317,7 @@
                         .build();
         final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future =
                 new AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>(handler);
-        connectorHandler.connect(socketAddress, new CompletionHandlerAdapter(future));
+        connectorHandler.connect(getSocketAddress(), new CompletionHandlerAdapter(future));
         return future;
     }
 
@@ -299,14 +327,23 @@
      * @return The address of the Directory Server.
      */
     public InetSocketAddress getSocketAddress() {
-        return socketAddress;
+        if (socketAddress != null) {
+            return socketAddress;
+        }
+        return new InetSocketAddress(host, port);
     }
 
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
         builder.append("LDAPConnectionFactory(");
-        builder.append(getSocketAddress().toString());
+        if (socketAddress != null) {
+            builder.append(socketAddress.toString());
+        } else {
+            builder.append(host);
+            builder.append(':');
+            builder.append(port);
+        }
         builder.append(')');
         return builder.toString();
     }
diff --git a/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java b/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
index 08eb75e..cbd9eb9 100644
--- a/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
+++ b/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
@@ -86,7 +86,9 @@
      *            The address of the Directory Server.
      * @throws NullPointerException
      *             If {@code address} was {@code null}.
+     * @deprecated use {@link #LDAPConnectionFactory(String, int)} instead.
      */
+    @Deprecated
     public LDAPConnectionFactory(final InetSocketAddress address) {
         this(address, new LDAPOptions());
     }
@@ -101,7 +103,10 @@
      *            The LDAP options to use when creating connections.
      * @throws NullPointerException
      *             If {@code address} or {@code options} was {@code null}.
+     * @deprecated use {@link #LDAPConnectionFactory(String, int,
+     * org.forgerock.opendj.ldap.LDAPOptions)} instead.
      */
+    @Deprecated
     public LDAPConnectionFactory(final InetSocketAddress address, final LDAPOptions options) {
         Validator.ensureNotNull(address, options);
         this.impl = new LDAPConnectionFactoryImpl(address, options);
@@ -139,8 +144,7 @@
      */
     public LDAPConnectionFactory(final String host, final int port, final LDAPOptions options) {
         Validator.ensureNotNull(host, options);
-        final InetSocketAddress address = new InetSocketAddress(host, port);
-        this.impl = new LDAPConnectionFactoryImpl(address, options);
+        this.impl = new LDAPConnectionFactoryImpl(host, port, options);
     }
 
     /**
diff --git a/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java b/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
index bc49974..fc7ffff 100644
--- a/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
+++ b/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
@@ -22,7 +22,7 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
- *      Portions copyright 2011-2013 ForgeRock AS
+ *      Portions copyright 2011-2014 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -43,6 +43,8 @@
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -133,7 +135,7 @@
 
     @DataProvider
     Object[][] connectionFactories() throws Exception {
-        Object[][] factories = new Object[21][1];
+        Object[][] factories = new Object[27][1];
 
         // HeartBeatConnectionFactory
         // Use custom search request.
@@ -141,26 +143,45 @@
                 Requests.newSearchRequest("uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT,
                         "objectclass=*", "cn");
 
+        SocketAddress addr = getServerSocketAddress();
+        assertTrue(addr instanceof InetSocketAddress);
+        InetSocketAddress socketAddress = (InetSocketAddress) addr;
+
         factories[0][0] =
                 Connections.newHeartBeatConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), 1000, 500, TimeUnit.MILLISECONDS, request);
+                        socketAddress), 1000, 500, TimeUnit.MILLISECONDS, request);
+        factories[1][0] =
+                Connections.newHeartBeatConnectionFactory(new LDAPConnectionFactory(
+                        socketAddress.getHostName(), socketAddress.getPort()), 1000, 500,
+                        TimeUnit.MILLISECONDS, request);
 
         // InternalConnectionFactory
-        factories[1][0] = Connections.newInternalConnectionFactory(LDAPServer.getInstance(), null);
+        factories[2][0] = Connections.newInternalConnectionFactory(LDAPServer.getInstance(), null);
 
         // AuthenticatedConnectionFactory
-        factories[2][0] =
-                new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), Requests.newSimpleBindRequest("", new char[0]));
-
-        // AuthenticatedConnectionFactory with multi-stage SASL
         factories[3][0] =
                 new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), Requests.newCRAMMD5SASLBindRequest("id:user",
+                        socketAddress), Requests.newSimpleBindRequest("", new char[0]));
+        factories[4][0] =
+                new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
+                        socketAddress.getHostName(), socketAddress.getPort()),
+                        Requests.newSimpleBindRequest("", new char[0]));
+
+        // AuthenticatedConnectionFactory with multi-stage SASL
+        factories[5][0] =
+                new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
+                        socketAddress), Requests.newCRAMMD5SASLBindRequest("id:user",
+                            "password".toCharArray()));
+        factories[6][0] =
+                new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
+                        socketAddress.getHostName(), socketAddress.getPort()),
+                        Requests.newCRAMMD5SASLBindRequest("id:user",
                             "password".toCharArray()));
 
         // LDAPConnectionFactory with default options
-        factories[4][0] = new LDAPConnectionFactory(getServerSocketAddress());
+        factories[7][0] = new LDAPConnectionFactory(socketAddress);
+        factories[8][0] = new LDAPConnectionFactory(socketAddress.getHostName(),
+                socketAddress.getPort());
 
         // LDAPConnectionFactory with startTLS
         SSLContext sslContext =
@@ -174,16 +195,24 @@
                                     "SSL_DH_anon_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_RC4_128_MD5",
                                     "TLS_DH_anon_WITH_AES_128_CBC_SHA",
                                     "TLS_DH_anon_WITH_AES_256_CBC_SHA" });
-        factories[5][0] = new LDAPConnectionFactory(getServerSocketAddress(), options);
+        factories[9][0] = new LDAPConnectionFactory(socketAddress, options);
+        factories[10][0] = new LDAPConnectionFactory(socketAddress.getHostName(),
+                socketAddress.getPort(), options);
 
         // startTLS + SASL confidentiality
         // Use IP address here so that DIGEST-MD5 host verification works if
         // local host name is not localhost (e.g. on some machines it might be
         // localhost.localdomain).
         // FIXME: enable QOP once OPENDJ-514 is fixed.
-        factories[6][0] =
+        factories[11][0] =
                 new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress(), options), Requests.newDigestMD5SASLBindRequest(
+                        socketAddress, options), Requests.newDigestMD5SASLBindRequest(
+                            "id:user", "password".toCharArray()).setCipher(
+                                DigestMD5SASLBindRequest.CIPHER_LOW));
+        factories[12][0] =
+                new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
+                        socketAddress.getHostName(), socketAddress.getPort(), options),
+                        Requests.newDigestMD5SASLBindRequest(
                             "id:user", "password".toCharArray()).setCipher(
                                 DigestMD5SASLBindRequest.CIPHER_LOW));
 
@@ -197,45 +226,45 @@
                         getServerSocketAddress()), "online");
 
         // Connection pools.
-        factories[7][0] = Connections.newFixedConnectionPool(onlineServer, 10);
+        factories[13][0] = Connections.newFixedConnectionPool(onlineServer, 10);
 
         // Round robin.
-        factories[8][0] =
+        factories[14][0] =
                 Connections.newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
                         onlineServer, offlineServer1)));
-        factories[9][0] = factories[8][0];
-        factories[10][0] = factories[8][0];
-        factories[11][0] =
+        factories[15][0] = factories[14][0];
+        factories[16][0] = factories[14][0];
+        factories[17][0] =
                 Connections.newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
                         offlineServer1, onlineServer)));
-        factories[12][0] =
+        factories[18][0] =
                 Connections.newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
                         offlineServer1, offlineServer2, onlineServer)));
-        factories[13][0] =
+        factories[19][0] =
                 Connections.newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays
                         .<ConnectionFactory> asList(Connections.newFixedConnectionPool(
                                 offlineServer1, 10), Connections.newFixedConnectionPool(
                                 onlineServer, 10))));
 
         // Fail-over.
-        factories[14][0] =
+        factories[20][0] =
                 Connections.newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
                         onlineServer, offlineServer1)));
-        factories[15][0] = factories[14][0];
-        factories[16][0] = factories[14][0];
-        factories[17][0] =
+        factories[21][0] = factories[20][0];
+        factories[22][0] = factories[20][0];
+        factories[23][0] =
                 Connections.newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
                         offlineServer1, onlineServer)));
-        factories[18][0] =
+        factories[24][0] =
                 Connections.newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
                         offlineServer1, offlineServer2, onlineServer)));
-        factories[19][0] =
+        factories[25][0] =
                 Connections.newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays
                         .<ConnectionFactory> asList(Connections.newFixedConnectionPool(
                                 offlineServer1, 10), Connections.newFixedConnectionPool(
                                 onlineServer, 10))));
 
-        factories[20][0] = Connections.newFixedConnectionPool(onlineServer, 10);
+        factories[26][0] = Connections.newFixedConnectionPool(onlineServer, 10);
 
         return factories;
     }

--
Gitblit v1.10.0