21
21
* questions.
22
22
*/
23
23
24
- /**
24
+ /*
25
25
* @test
26
- * @run main/othervm DeadSSLLdapTimeoutTest
27
26
* @bug 8141370
28
27
* @key intermittent
28
+ * @library /lib/testlibrary
29
+ * @build DeadSSLSocketFactory
30
+ * @run main/othervm DeadSSLLdapTimeoutTest
29
31
*/
30
32
31
- import java .net .Socket ;
33
+ import java .io .EOFException ;
34
+ import java .io .IOException ;
35
+ import java .net .InetAddress ;
36
+ import java .net .InetSocketAddress ;
32
37
import java .net .ServerSocket ;
38
+ import java .net .Socket ;
39
+ import java .net .SocketAddress ;
33
40
import java .net .SocketTimeoutException ;
34
- import java .io .*;
35
- import javax .naming .*;
36
- import javax .naming .directory .*;
37
- import java .util .List ;
41
+ import javax .naming .Context ;
42
+ import javax .naming .InitialContext ;
43
+ import javax .naming .NamingException ;
38
44
import java .util .Hashtable ;
39
- import java .util .ArrayList ;
40
45
import java .util .concurrent .Callable ;
41
- import java .util .concurrent .ExecutionException ;
42
- import java .util .concurrent .Executors ;
43
- import java .util .concurrent .ExecutorService ;
44
- import java .util .concurrent .Future ;
45
- import java .util .concurrent .ScheduledExecutorService ;
46
- import java .util .concurrent .ScheduledFuture ;
47
- import java .util .concurrent .TimeoutException ;
46
+ import java .util .concurrent .CountDownLatch ;
48
47
import java .util .concurrent .TimeUnit ;
48
+ import javax .naming .directory .InitialDirContext ;
49
49
import javax .net .ssl .SSLHandshakeException ;
50
50
51
- import static java .util .concurrent .TimeUnit .MILLISECONDS ;
51
+ import jdk .testlibrary .net .URIBuilder ;
52
+
52
53
import static java .util .concurrent .TimeUnit .NANOSECONDS ;
53
54
54
55
@@ -57,26 +58,26 @@ class DeadServerTimeoutSSLTest implements Callable {
57
58
Hashtable env ;
58
59
DeadSSLServer server ;
59
60
boolean passed = false ;
60
- private int HANGING_TEST_TIMEOUT = 20_000 ;
61
61
62
62
public DeadServerTimeoutSSLTest (Hashtable env ) throws IOException {
63
- this .server = new DeadSSLServer ();
63
+ SocketAddress sockAddr = new InetSocketAddress (
64
+ InetAddress .getLoopbackAddress (), 0 );
65
+ this .server = new DeadSSLServer (sockAddr );
64
66
this .env = env ;
65
67
}
66
68
67
- public void performOp (InitialContext ctx ) throws NamingException {}
68
-
69
- public void handleNamingException (NamingException e , long start , long end ) {
69
+ public void handleNamingException (NamingException e ) {
70
70
if (e .getCause () instanceof SocketTimeoutException
71
71
|| e .getCause ().getCause () instanceof SocketTimeoutException ) {
72
72
// SSL connect will timeout via readReply using
73
73
// SocketTimeoutException
74
- e . printStackTrace ( );
74
+ System . out . println ( "PASS: Observed expected SocketTimeoutException" );
75
75
pass ();
76
76
} else if (e .getCause () instanceof SSLHandshakeException
77
77
&& e .getCause ().getCause () instanceof EOFException ) {
78
78
// test seems to be failing intermittently on some
79
79
// platforms.
80
+ System .out .println ("PASS: Observed expected SSLHandshakeException/EOFException" );
80
81
pass ();
81
82
} else {
82
83
fail (e );
@@ -92,6 +93,7 @@ public void fail() {
92
93
}
93
94
94
95
public void fail (Exception e ) {
96
+ System .err .println ("FAIL: Unexpected exception was observed:" + e .getMessage ());
95
97
throw new RuntimeException ("Test failed" , e );
96
98
}
97
99
@@ -106,55 +108,106 @@ boolean shutItDown(InitialContext ctx) {
106
108
107
109
public Boolean call () {
108
110
InitialContext ctx = null ;
109
- ScheduledFuture killer = null ;
110
- long start = System .nanoTime ();
111
111
112
112
try {
113
- while (!server .accepting ())
114
- Thread .sleep (200 ); // allow the server to start up
113
+ server .serverStarted .await (); // Wait for the server to start-up
115
114
Thread .sleep (200 ); // to be sure
116
115
117
- env .put (Context .PROVIDER_URL , "ldap://localhost:" +
118
- server .getLocalPort ());
116
+ env .put (Context .PROVIDER_URL ,
117
+ URIBuilder .newBuilder ()
118
+ .scheme ("ldap" )
119
+ .loopback ()
120
+ .port (server .getLocalPort ())
121
+ .buildUnchecked ().toString ()
122
+ );
119
123
124
+ long start = System .nanoTime ();
120
125
try {
121
126
ctx = new InitialDirContext (env );
122
- performOp (ctx );
123
127
fail ();
124
128
} catch (NamingException e ) {
125
129
long end = System .nanoTime ();
126
130
System .out .println (this .getClass ().toString () + " - elapsed: "
127
131
+ NANOSECONDS .toMillis (end - start ));
128
- handleNamingException (e , start , end );
132
+ handleNamingException (e );
129
133
} finally {
130
- if ( killer != null && ! killer . isDone ())
131
- killer . cancel ( true );
134
+ // Stop the server side thread
135
+ server . testDone . countDown ( );
132
136
shutItDown (ctx );
133
137
server .close ();
134
138
}
135
139
return passed ;
136
- } catch (IOException | InterruptedException e ) {
140
+ } catch (IOException | InterruptedException e ) {
137
141
throw new RuntimeException (e );
138
142
}
139
143
}
140
144
}
141
145
142
146
class DeadSSLServer extends Thread {
143
147
ServerSocket serverSock ;
144
- boolean accepting = false ;
145
-
146
- public DeadSSLServer () throws IOException {
147
- this .serverSock = new ServerSocket (0 );
148
+ // Latch to be used by client to wait for server to start
149
+ CountDownLatch serverStarted = new CountDownLatch (1 );
150
+
151
+ // Latch to be used by server thread to wait for client to finish testing
152
+ CountDownLatch testDone = new CountDownLatch (1 );
153
+
154
+ public DeadSSLServer (SocketAddress socketAddress ) throws IOException {
155
+ // create unbound server socket
156
+ ServerSocket srvSock = new ServerSocket ();
157
+ // bind it to the address provided
158
+ srvSock .bind (socketAddress );
159
+ this .serverSock = srvSock ;
148
160
start ();
149
161
}
150
162
151
163
public void run () {
152
- while (true ) {
153
- try {
154
- accepting = true ;
155
- Socket socket = serverSock .accept ();
164
+ // Signal client to proceed with the test
165
+ serverStarted .countDown ();
166
+ while (true ) {
167
+ try (Socket acceptedSocket = serverSock .accept ()) {
168
+ System .err .println ("Accepted connection:" + acceptedSocket );
169
+ int iteration = 0 ;
170
+ // Wait for socket to get opened by DeadSSLSocketFactory and connected to the test server
171
+ while (iteration ++ < 20 ) {
172
+ if (DeadSSLSocketFactory .firstCreatedSocket .get () != null &&
173
+ DeadSSLSocketFactory .firstCreatedSocket .get ().isConnected ()) {
174
+ break ;
175
+ }
176
+ try {
177
+ TimeUnit .MILLISECONDS .sleep (50 );
178
+ } catch (InterruptedException ie ) {
179
+ }
180
+ }
181
+ Socket clientSideSocket = DeadSSLSocketFactory .firstCreatedSocket .get ();
182
+ System .err .printf ("Got SSLSocketFactory connection after %d iterations: %s%n" ,
183
+ iteration , clientSideSocket );
184
+
185
+ if (clientSideSocket == null || !clientSideSocket .isConnected ()) {
186
+ // If after 1000 ms client side connection is not opened - probably other local process
187
+ // tried to connect to the test server socket. Close current connection and retry accept.
188
+ continue ;
189
+ } else {
190
+ // Check if accepted socket is connected to the LDAP client
191
+ if (acceptedSocket .getLocalPort () == clientSideSocket .getPort () &&
192
+ acceptedSocket .getPort () == clientSideSocket .getLocalPort () &&
193
+ acceptedSocket .getInetAddress ().equals (clientSideSocket .getLocalAddress ())) {
194
+ System .err .println ("Accepted connection is originated from LDAP client:" + acceptedSocket );
195
+ try {
196
+ // Give LDAP client time to fully establish the connection.
197
+ // When client is done - the accepted socket will be closed
198
+ testDone .await ();
199
+ } catch (InterruptedException e ) {
200
+ }
201
+ break ;
202
+ } else {
203
+ // If accepted socket is not from the LDAP client - the accepted connection will be closed and new
204
+ // one will be accepted
205
+ System .err .println ("SSLSocketFactory connection has been established, but originated not from" +
206
+ " the test's LDAP client:" + acceptedSocket );
207
+ }
208
+ }
156
209
} catch (Exception e ) {
157
- break ;
210
+ System . err . println ( "Server socket. Failure to accept connection:" + e . getMessage ()) ;
158
211
}
159
212
}
160
213
}
@@ -163,28 +216,26 @@ public int getLocalPort() {
163
216
return serverSock .getLocalPort ();
164
217
}
165
218
166
- public boolean accepting () {
167
- return accepting ;
168
- }
169
-
170
219
public void close () throws IOException {
171
220
serverSock .close ();
172
221
}
173
222
}
174
223
175
224
public class DeadSSLLdapTimeoutTest {
225
+ // com.sun.jndi.ldap.connect.timeout value to set
226
+ static final String CONNECT_TIMEOUT_MS = "10" ;
227
+
228
+ // com.sun.jndi.ldap.read.timeout value to set
229
+ static final String READ_TIMEOUT_MS = "3000" ;
176
230
177
231
static Hashtable createEnv () {
178
232
Hashtable env = new Hashtable (11 );
179
233
env .put (Context .INITIAL_CONTEXT_FACTORY ,
180
- "com.sun.jndi.ldap.LdapCtxFactory" );
234
+ "com.sun.jndi.ldap.LdapCtxFactory" );
181
235
return env ;
182
236
}
183
237
184
238
public static void main (String [] args ) throws Exception {
185
-
186
- InitialContext ctx = null ;
187
-
188
239
//
189
240
// Running this test serially as it seems to tickle a problem
190
241
// on older kernels
@@ -193,19 +244,24 @@ public static void main(String[] args) throws Exception {
193
244
// and ssl enabled
194
245
// this should exit with a SocketTimeoutException as the root cause
195
246
// it should also use the connect timeout instead of the read timeout
196
- System .out .println ("Running connect timeout test with 10ms connect timeout, 3000ms read timeout & SSL" );
247
+ System .out .printf ("Running connect timeout test with %sms connect timeout," +
248
+ " %sms read timeout & SSL%n" ,
249
+ CONNECT_TIMEOUT_MS , READ_TIMEOUT_MS );
250
+
197
251
Hashtable sslenv = createEnv ();
198
- sslenv .put ("com.sun.jndi.ldap.connect.timeout" , "10" );
199
- sslenv .put ("com.sun.jndi.ldap.read.timeout" , "3000" );
252
+ // Setup connect timeout environment property
253
+ sslenv .put ("com.sun.jndi.ldap.connect.timeout" , CONNECT_TIMEOUT_MS );
254
+ // Setup read timeout environment property
255
+ sslenv .put ("com.sun.jndi.ldap.read.timeout" , READ_TIMEOUT_MS );
256
+ // Setup DeadSSLSocketFactory to track the client's first LDAP connection
257
+ sslenv .put ("java.naming.ldap.factory.socket" , "DeadSSLSocketFactory" );
258
+ // Use SSL protocol
200
259
sslenv .put (Context .SECURITY_PROTOCOL , "ssl" );
201
- boolean testFailed =
202
- (new DeadServerTimeoutSSLTest (sslenv ).call ()) ? false : true ;
203
260
261
+ boolean testFailed = !new DeadServerTimeoutSSLTest (sslenv ).call ();
204
262
if (testFailed ) {
205
263
throw new AssertionError ("some tests failed" );
206
264
}
207
-
208
265
}
209
-
210
266
}
211
267
1 commit comments
openjdk-notifier[bot] commentedon Oct 3, 2024
Review
Issues