1 import java.net.Socket;
   2 import java.net.ServerSocket;
   3 import java.io.*;
   4 import javax.naming.*;
   5 import javax.naming.directory.*;
   6 import java.util.Hashtable;
   7 import java.util.concurrent.*;
   8 
   9 /**
  10  * @test
  11  * @compile TestDnsProvider.java
  12  * @run main/othervm LdapDnsProviderTest
  13  * @modules java.naming/com.sun.jndi.ldap
  14  * @bug 8160768
  15  * @summary ctx provider tests for ldap
  16  */
  17 
  18 class ProviderTest implements Callable {
  19 
  20     private final String expected;
  21     private final ScheduledExecutorService killSwitchPool;
  22     private final LdapTestServer server;
  23     private final Hashtable env = new Hashtable(11);
  24     private final int HANGING_TEST_TIMEOUT = 1000;
  25 
  26     public ProviderTest(LdapTestServer server,
  27                         ScheduledExecutorService killSwitchPool,
  28                         String expected,
  29                         String dnsProvider)
  30             throws IOException
  31     {
  32         this.server = server;
  33         this.killSwitchPool = killSwitchPool;
  34         this.expected = expected;
  35         env.put("com.sun.jndi.ldap.dnsProvider", dnsProvider);
  36         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
  37     }
  38 
  39     boolean shutItDown(InitialContext ctx) {
  40         try {
  41             if (ctx != null) ctx.close();
  42             return true;
  43         } catch (NamingException ex) {
  44             return false;
  45         }
  46     }
  47 
  48     public Boolean call() {
  49         boolean passed;
  50         InitialContext ctx = null;
  51         ScheduledFuture killer = null;
  52         // String providerUrl = "ldap://localhost:" + server.getLocalPort();
  53         String providerUrl = "ldap:///dc=example,dc=com";
  54 
  55         try {
  56             while(!server.accepting()) {
  57                 Thread.sleep(200); // allow the server to start up
  58             }
  59             Thread.sleep(200); // to be sure
  60 
  61             // if this is a hanging test, scheduled a thread to
  62             // interrupt after a certain time
  63             if (killSwitchPool != null) {
  64                 final Thread current = Thread.currentThread();
  65                 killer = killSwitchPool.schedule(
  66                     new Callable<Void>() {
  67                         public Void call() throws Exception {
  68                             current.interrupt();
  69                             return null;
  70                         }
  71                     }, HANGING_TEST_TIMEOUT, TimeUnit.MILLISECONDS);
  72             }
  73 
  74             env.put(Context.PROVIDER_URL, providerUrl);
  75 
  76             try {
  77                 ctx = new InitialDirContext(env);
  78                 SearchControls scl = new SearchControls();
  79                 scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
  80                 NamingEnumeration<SearchResult> answer = ((InitialDirContext)ctx)
  81                         .search("ou=People,o=Test", "(objectClass=*)", scl);
  82                 throw new RuntimeException("Search should not complete");
  83             } catch (NamingException e) {
  84                 passed = e.toString().indexOf(expected) > -1;
  85             } finally {
  86                 if (killer != null && !killer.isDone()) {
  87                     killer.cancel(true);
  88                 }
  89                 shutItDown(ctx);
  90                 server.close();
  91             }
  92             return passed;
  93         } catch (IOException|InterruptedException e) {
  94             throw new RuntimeException(e);
  95         }
  96     }
  97 }
  98 
  99 
 100 class LdapTestServer extends Thread {
 101     ServerSocket serverSock;
 102     boolean accepting = false;
 103     private byte[] bindResponse = {
 104         0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
 105         0x01, 0x00, 0x04, 0x00, 0x04, 0x00
 106     };
 107 
 108     public LdapTestServer() throws IOException {
 109         this.serverSock = new ServerSocket(0);
 110         start();
 111     }
 112 
 113     public int getLocalPort() {
 114         return serverSock.getLocalPort();
 115     }
 116 
 117     public boolean accepting() {
 118         return accepting;
 119     }
 120 
 121     public void close() throws IOException {
 122         serverSock.close();
 123     }
 124 
 125     public void run() {
 126         try {
 127             accepting = true;
 128             Socket socket = serverSock.accept();
 129             InputStream in = socket.getInputStream();
 130             OutputStream out = socket.getOutputStream();
 131 
 132             // Read the LDAP BindRequest
 133             while (in.read() != -1) {
 134                 in.skip(in.available());
 135                 break;
 136             }
 137 
 138             // Write an LDAP BindResponse
 139             out.write(bindResponse);
 140             out.flush();
 141         } catch (IOException e) {
 142             // ignore
 143         }
 144     }
 145 }
 146 
 147 public class LdapDnsProviderTest {
 148 
 149     private static final ExecutorService testPool =
 150         Executors.newFixedThreadPool(1);
 151     private static final ScheduledExecutorService killSwitchPool =
 152         Executors.newScheduledThreadPool(1);
 153 
 154     public static void main(String[] args) throws Exception {
 155         LdapTestServer server = new LdapTestServer();
 156         try {
 157             runTest(server, "yupyupyup:389", TestDnsProvider.class.getName());
 158             runTest(server, "localhost:389",
 159                     com.sun.jndi.ldap.DefaultLdapDnsProvider.class.getName());
 160         } finally {
 161             LdapDnsProviderTest.killSwitchPool.shutdown();
 162             LdapDnsProviderTest.testPool.shutdown();
 163         }
 164     }
 165 
 166     private static boolean runTest(LdapTestServer server,
 167                                    String expected,
 168                                    String dnsProvider)
 169             throws IOException, InterruptedException, ExecutionException
 170     {
 171         Future test = testPool.submit(
 172                 new ProviderTest(
 173                         server, killSwitchPool, expected, dnsProvider));
 174 
 175         while (!test.isDone()) {
 176             if ((Boolean) test.get()) {
 177                 return true;
 178             }
 179         }
 180         throw new AssertionError("FAILED: " + expected + ", " + dnsProvider);
 181     }
 182 
 183 }
 184