1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 7094377 8000487 6176036 7056489 27 * @summary Timeout tests for ldap 28 */ 29 30 import com.sun.jndi.ldap.Connection; 31 32 import java.net.Socket; 33 import java.net.ServerSocket; 34 import java.net.SocketTimeoutException; 35 import java.io.*; 36 import javax.naming.*; 37 import javax.naming.directory.*; 38 import java.util.Hashtable; 39 import java.util.concurrent.Callable; 40 import java.util.concurrent.Executors; 41 import java.util.concurrent.ScheduledExecutorService; 42 import java.util.concurrent.ScheduledFuture; 43 44 import static java.util.concurrent.TimeUnit.MILLISECONDS; 45 import static java.util.concurrent.TimeUnit.NANOSECONDS; 46 47 public class LdapTimeoutTest { 48 private static final ScheduledExecutorService pool = 49 Executors.newScheduledThreadPool(1); 50 static volatile int passed = 0, failed = 0; 51 static void pass() {passed++;} 52 static void fail() {failed++; Thread.dumpStack();} 53 54 public static void main(String[] args) throws Exception { 55 ServerSocket serverSock = new ServerSocket(0); 56 Server s = new Server(serverSock); 57 s.start(); 58 Thread.sleep(200); 59 60 Hashtable env = new Hashtable(11); 61 env.put(Context.INITIAL_CONTEXT_FACTORY, 62 "com.sun.jndi.ldap.LdapCtxFactory"); 63 env.put(Context.PROVIDER_URL, "ldap://localhost:" + 64 serverSock.getLocalPort()); 65 66 env.put(Context.SECURITY_AUTHENTICATION,"simple"); 67 68 env.put(Context.SECURITY_PRINCIPAL, "user"); 69 env.put(Context.SECURITY_CREDENTIALS, "password"); 70 71 InitialContext ctx = null; 72 try { 73 new LdapTimeoutTest().deadServerNoTimeout(env); 74 75 env.put("com.sun.jndi.ldap.connect.timeout", "10"); 76 env.put("com.sun.jndi.ldap.read.timeout", "3000"); 77 new LdapTimeoutTest().ldapReadTimeoutTest(env, false); 78 new LdapTimeoutTest().ldapReadTimeoutTest(env, true); 79 new LdapTimeoutTest().simpleAuthConnectTest(env); 80 } finally { 81 s.interrupt(); 82 LdapTimeoutTest.pool.shutdown(); 83 } 84 85 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 86 if (failed > 0) throw new AssertionError("Some tests failed"); 87 } 88 89 void ldapReadTimeoutTest(Hashtable env, boolean ssl) { 90 InitialContext ctx = null; 91 if (ssl) env.put(Context.SECURITY_PROTOCOL, "ssl"); 92 ScheduledFuture killer = killSwitch(5_000); 93 long start = System.nanoTime(); 94 try { 95 ctx = new InitialDirContext(env); 96 SearchControls scl = new SearchControls(); 97 scl.setSearchScope(SearchControls.SUBTREE_SCOPE); 98 NamingEnumeration<SearchResult> answer = ((InitialDirContext)ctx) 99 .search("ou=People,o=JNDITutorial", "(objectClass=*)", scl); 100 // shouldn't reach here 101 fail(); 102 } catch (NamingException e) { 103 if (ssl) { 104 if (e.getCause() instanceof SocketTimeoutException) { 105 pass(); 106 } else if (e.getCause() instanceof InterruptedIOException) { 107 Thread.interrupted(); 108 fail(); 109 } 110 } else { 111 pass(); 112 } 113 } finally { 114 if (!shutItDown(killer, ctx)) fail(); 115 } 116 } 117 118 void simpleAuthConnectTest(Hashtable env) { 119 InitialContext ctx = null; 120 ScheduledFuture killer = killSwitch(5_000); 121 long start = System.nanoTime(); 122 try { 123 ctx = new InitialDirContext(env); 124 // shouldn't reach here 125 System.err.println("Fail: InitialDirContext succeeded"); 126 fail(); 127 } catch (NamingException e) { 128 long end = System.nanoTime(); 129 if (e.getCause() instanceof SocketTimeoutException) { 130 if (NANOSECONDS.toMillis(end - start) < 2_900) { 131 pass(); 132 } else { 133 System.err.println("Fail: Waited too long"); 134 fail(); 135 } 136 } else if (e.getCause() instanceof InterruptedIOException) { 137 Thread.interrupted(); 138 fail(); 139 } else { 140 fail(); 141 } 142 } finally { 143 if (!shutItDown(killer, ctx)) fail(); 144 } 145 } 146 147 void deadServerNoTimeout(Hashtable env) { 148 InitialContext ctx = null; 149 ScheduledFuture killer = killSwitch(30_000); 150 long start = System.nanoTime(); 151 try { 152 ctx = new InitialDirContext(env); 153 SearchControls scl = new SearchControls(); 154 scl.setSearchScope(SearchControls.SUBTREE_SCOPE); 155 NamingEnumeration<SearchResult> answer = ((InitialDirContext)ctx) 156 .search("ou=People,o=JNDITutorial", "(objectClass=*)", scl); 157 // shouldn't reach here 158 fail(); 159 } catch (NamingException e) { 160 long end = System.nanoTime(); 161 long elapsed = NANOSECONDS.toMillis(end - start); 162 if (elapsed < Connection.DEFAULT_READ_TIMEOUT_MILLIS) { 163 System.err.printf( 164 "fail: timeout should be at least %s ms, actual time is %s ms", 165 Connection.DEFAULT_READ_TIMEOUT_MILLIS, 166 elapsed); 167 e.printStackTrace(); 168 fail(); 169 } else { 170 pass(); 171 } 172 } finally { 173 if (!shutItDown(killer, ctx)) fail(); 174 } 175 } 176 177 boolean shutItDown(ScheduledFuture killer, InitialContext ctx) { 178 killer.cancel(true); 179 try { 180 if (ctx != null) ctx.close(); 181 return true; 182 } catch (NamingException ex) { 183 return false; 184 } 185 } 186 187 ScheduledFuture killSwitch(int ms) { 188 final Thread current = Thread.currentThread(); 189 return LdapTimeoutTest.pool.schedule(new Callable<Void>() { 190 public Void call() throws Exception { 191 System.err.println("Fail: killSwitch()"); 192 System.exit(0); 193 return null; 194 } 195 }, ms, MILLISECONDS); 196 } 197 198 static class Server extends Thread { 199 final ServerSocket serverSock; 200 201 Server(ServerSocket serverSock) { 202 this.serverSock = serverSock; 203 } 204 205 public void run() { 206 try { 207 Socket socket = serverSock.accept(); 208 } catch (IOException e) {} 209 } 210 } 211 } 212